home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / screen32.lha / screen-3.2b / screen.c < prev    next >
C/C++ Source or Header  |  1992-10-22  |  86KB  |  3,967 lines

  1. /* Copyright (c) 1991
  2.  *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
  3.  *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
  4.  * Copyright (c) 1987 Oliver Laumann
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 1, or (at your option)
  9.  * any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program (see the file COPYING); if not, write to the
  18.  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  * Noteworthy contributors to screen's design and implementation:
  21.  *    Wayne Davison (davison@borland.com)
  22.  *    Patrick Wolfe (pat@kai.com, kailand!pat)
  23.  *    Bart Schaefer (schaefer@cse.ogi.edu)
  24.  *    Nathan Glasser (nathan@brokaw.lcs.mit.edu)
  25.  *    Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu)
  26.  *    Howard Chu (hyc@hanauma.jpl.nasa.gov)
  27.  *    Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
  28.  *    Markku Jarvinen (mta@{cc,cs,ee}.tut.fi)
  29.  *    Marc Boucher (marc@CAM.ORG)
  30.  *
  31.  ****************************************************************
  32.  */
  33.  
  34. #ifndef lint
  35.   static char rcs_id[] = "$Id: screen.c,v 1.2 92/02/03 02:28:05 jnweiger Exp $ FAU";
  36. #endif
  37.  
  38.  
  39. #include <sys/param.h>
  40. /* #include <signal.h> */
  41. #include <ctype.h>
  42. #include <pwd.h>
  43. #include <fcntl.h>
  44. #ifdef sgi
  45. # include <sys/sysmacros.h>
  46. #endif /* sgi */
  47. #if !defined(sun) && !defined(B43) && !defined(ISC)
  48. # include <time.h>
  49. #endif
  50. /*
  51.  * Gee!! We should reverse that #if! 
  52.  */
  53. #if defined(sun) || defined(_AIX) || defined(sysV68) || defined(MIPS) || defined(GOULD_NP1) || defined(B43) || defined(ISC) || defined(apollo) || defined(BSDI) || defined(sgi)
  54. # include <sys/time.h>
  55. #endif
  56. #if defined(M_XENIX) || defined(M_UNIX)
  57. #include <sys/select.h> /* for timeval */
  58. #endif
  59. #include <sys/types.h>
  60. #ifdef ISC
  61. # include <sys/bsdtypes.h>
  62. #endif
  63. #if !defined(sysV68) && !defined(M_XENIX)
  64. # include <sys/wait.h>
  65. #endif
  66. #include <sys/stat.h>
  67. #ifndef sgi
  68. # include <sys/file.h>
  69. #endif /* sgi */
  70. #ifndef sun
  71. # include <sys/ioctl.h>
  72. #endif /* sun */
  73.  
  74. #include <signal.h>
  75. #if defined(SVR4) && !defined(NSIG)
  76. #define NSIG 32
  77. #endif
  78.  
  79. #include "config.h"
  80.  
  81. #ifdef SHADOWPW
  82. # include <shadow.h>
  83. #endif /* SHADOWPW */
  84.  
  85. #ifdef SVR4
  86. # include <sys/stropts.h>
  87. #endif
  88.  
  89. #ifdef SYSV
  90. # include <sys/utsname.h>
  91. #endif
  92.  
  93. #if defined(_SEQUENT_) 
  94. /* for the FD.. stuff */
  95. # include <sys/select.h>
  96. #endif 
  97.  
  98. #if defined(sequent) || defined(SVR4)
  99. # include <sys/resource.h>
  100. #endif /* sequent || SVR4 */
  101.  
  102. #ifdef ISC
  103. # include <sys/tty.h>
  104. # include <sys/sioctl.h>
  105. # include <sys/pty.h>
  106. #endif
  107.  
  108. #include "screen.h"
  109.  
  110. #include "patchlevel.h"
  111.  
  112. #if defined(xelos) || defined(sysV68) || defined(M_XENIX)
  113.  struct passwd *getpwuid __P((uid_t));
  114.  struct passwd *getpwnam __P((char *));
  115. #endif
  116.  
  117. #ifdef USEVARARGS
  118. # if defined(__STDC__)
  119. #  include <stdarg.h>
  120. # else
  121. #  include <varargs.h>
  122. # endif
  123. #endif
  124.  
  125. #ifdef DEBUG
  126. FILE *dfp;
  127. #endif
  128.  
  129.  
  130. #ifdef COPY_PASTE
  131. extern char *copybuffer;    /* def in mark.c jw. */
  132. extern copylen;
  133. #endif /* COPY_PASTE */
  134.  
  135. extern char *blank, *null, Term[], screenterm[], **environ, *Termcap;
  136. int force_vt = 1, assume_LP = 0;
  137. extern int in_ovl;
  138. extern int ovl_blockfore;
  139. extern void (*ovl_process)();
  140. extern int help_page;
  141. extern int screenwidth, screenheight;
  142. extern char display_tty[];
  143. extern int default_width, default_height;
  144. extern int Z0width, Z1width;
  145. extern int ISO2022;
  146. extern int status, HS;
  147. extern char *Z0, *WS, *LastMsg;
  148. extern time_t TimeDisplayed;
  149. int BellDisplayed;
  150. int VBellWait, MsgWait, MsgMinWait;
  151.  
  152. /* tputs uses that: jw */
  153. extern short ospeed;
  154.  
  155. extern int flow, default_flow, wrap, visual_bell, default_monitor;
  156. extern int errno;
  157. extern sys_nerr;
  158. extern char *sys_errlist[];
  159. extern char mark_key_tab[];
  160.  
  161. #if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
  162. extern struct winsize glwz;
  163. #endif
  164.  
  165. static char *MakeWinMsg __P((char *, int));
  166. static void MakeNewEnv __P((void));
  167. static int Attach __P((int));
  168. static void Attacher __P((void));
  169. static void SigHandler __P((void));
  170. static sig_t AttacherSigInt __P(SIGPROTOARG);
  171. static sig_t SigChld __P(SIGPROTOARG);
  172. static sig_t SigInt __P(SIGPROTOARG);
  173. static sig_t CoreDump __P((int));
  174. static void DoWait __P((void));
  175. static sig_t Finit __P((int));
  176. static void InitKeytab __P((void));
  177. static void SetForeWindow __P((int));
  178. static int NextWindow __P((void));
  179. static int PreviousWindow __P((void));
  180. static int MoreWindows __P((void));
  181. static void FreeWindow __P((struct win *));
  182. static void execvpe __P((char *, char **, char **));
  183. static void LogToggle __P((void));
  184. static void ShowWindows __P((void));
  185. static void ShowTime __P((void));
  186. static void ShowInfo __P((void));
  187. static int OpenPTY __P((void));
  188. #ifdef PASSWORD
  189. static void trysend __P((int, struct msg *, char *));
  190. #endif
  191. #if defined(SIGWINCH) && defined(TIOCGWINSZ)
  192. static sig_t SigAttWinch __P(SIGPROTOARG);
  193. #endif
  194. static void fgtty __P((void));
  195. static void freetty __P((void));
  196. static void brktty __P((void));
  197.  
  198. #if defined(LOCK)
  199. static sig_t DoLock __P(SIGPROTOARG);
  200. static void LockTerminal __P((void));
  201. #endif
  202.  
  203. #ifdef COPY_PASTE
  204. static pastelen;
  205. static char *pastebuffer;
  206. #endif
  207. #ifdef PASSWORD
  208. extern char Password[];
  209. #endif
  210.  
  211. static struct passwd *ppp;
  212.  
  213. /* used for opening a new pty-pair: */
  214. static char PtyName[32], TtyName[32];
  215.  
  216. /* used for the attacher's tty: */
  217. static char *attach_tty;
  218.  
  219. char *ShellProg;
  220. char *ShellArgs[2];
  221. static char inbuf[MAXWIN][IOSIZE];
  222. static inlen[MAXWIN];
  223. static inbuf_ct;
  224. static ESCseen;
  225. static GotSignal;
  226.  
  227. static char DefaultShell[] = "/bin/sh";
  228. static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin";
  229.  
  230. #ifdef hpux
  231. char PtyProto[] = "/dev/ptym/ptyXY";
  232. char TtyProto[] = "/dev/pty/ttyXY";
  233. #else
  234. # if !(defined(sequent) || defined(_SEQUENT_) || defined(SVR4))
  235. static char PtyProto[] = "/dev/ptyXY";
  236. static char TtyProto[] = "/dev/ttyXY";
  237. # endif
  238. #endif /* hpux */
  239. int TtyMode = 0622;
  240. #ifdef SOCKDIR
  241. char *SockDir = SOCKDIR;
  242. #else
  243. char *SockDir = ".iscreen";
  244. #endif
  245. extern char SockPath[], *SockNamePtr, *SockName;
  246. int ServerSocket = -1;
  247. static char **NewEnv;
  248.  
  249. char *RcFileName = NULL;
  250. char Esc = Ctrl('a');
  251. char MetaEsc = 'a';
  252. char *home;
  253.  
  254. int HasWindow;
  255. char *LoginName;
  256. char *BellString;
  257. char *VisualBellString;
  258. char *ActivityString;
  259. char *BufferFile;
  260. char *PowDetachString;
  261. int auto_detach = 1;
  262. int iflag, rflag, dflag, lsflag, quietflag, wipeflag;
  263. int adaptflag, loginflag = -1, allflag;
  264. static intrc, startc, stopc;
  265. char HostName[MAXSTR];
  266. int Detached, Suspended;
  267. int DeadlyMsg = 1;
  268. int AttacherPid;    /* Non-Zero in child if we have an attacher */
  269. int MasterPid;
  270. int real_uid, real_gid, eff_uid, eff_gid;
  271. int default_histheight;
  272. int default_startup;
  273. int slowpaste;
  274.  
  275. #if defined(BSDJOBS) && !(defined(POSIX) || defined(SYSV))
  276. int DevTty = -1;
  277. #endif
  278.  
  279. #ifdef NETHACK
  280. int nethackflag = 0;
  281. #endif
  282.  
  283. struct mode OldMode, NewMode;
  284.  
  285. struct win *fore = NULL;
  286. int WinList = -1;
  287. int ForeNum;
  288. struct win *wtab[MAXWIN];
  289.  
  290. struct key ktab[256];
  291.  
  292. #ifndef FD_SET
  293. typedef struct fd_set
  294. {
  295.   int fd_bits[1];
  296. }      fd_set;
  297. # define FD_ZERO(fd) ((fd)->fd_bits[0] = 0)
  298. # define FD_SET(b, fd) ((fd)->fd_bits[0] |= 1 << (b))
  299. # define FD_ISSET(b, fd) ((fd)->fd_bits[0] & 1 << (b))
  300. # define FD_SETSIZE 32
  301. #endif
  302.  
  303.  
  304. #ifndef WTERMSIG
  305. # ifndef BSDWAIT /* if wait is NOT a union: */
  306. #  define WTERMSIG(status) (status & 0177)
  307. # else
  308. #  define WTERMSIG(status) status.w_T.w_Termsig 
  309. # endif
  310. #endif
  311.  
  312. #ifndef WIFCORESIG
  313. # ifndef BSDWAIT /* if wait is NOT a union: */
  314. #  define WIFCORESIG(status) (status & 0200)
  315. # else
  316. #  define WIFCORESIG(status) status.w_T.w_Coredump
  317. # endif
  318. #endif
  319.  
  320. #ifndef WEXITSTATUS
  321. # ifndef BSDWAIT /* if wait is NOT a union: */
  322. #  define WEXITSTATUS(status) ((status >> 8) & 0377)
  323. # else
  324. #  define WEXITSTATUS(status) status.w_T.w_Retcode
  325. # endif
  326. #endif
  327.  
  328. char *shellaka = NULL;
  329.  
  330. /*
  331.  * Do this last
  332.  */
  333. #include "extern.h"
  334.  
  335. /*
  336.  * XXX: Missing system header files.
  337.  */
  338. #ifdef USEVARARGS
  339. # ifndef VPRNT_DECLARED
  340. int vsprintf __P((char *, char *, va_list));
  341. # endif /* VPRNT_DECLARED */
  342. #endif
  343. int select __P((int, fd_set *, fd_set *, fd_set *, struct timeval *));
  344.  
  345. static void
  346. brktty()
  347. {
  348. #ifdef POSIX
  349.   setsid();        /* will break terminal affiliation */
  350. # ifdef BSD
  351.   ioctl(0, TIOCSCTTY, 0);
  352. # endif /* BSD */
  353. #else
  354. # ifdef SYSV
  355.   setpgrp();        /* will break terminal affiliation */
  356. # else
  357. #  ifdef BSDJOBS
  358.   if (DevTty)
  359.     if (ioctl(DevTty, TIOCNOTTY, (char *) 0) != 0)
  360.       debug2("brktty: ioctl(DevTty=%d, TIOCNOTTY, 0) = %d\n", DevTty, errno);
  361. #  endif
  362. # endif
  363. #endif
  364. }
  365.  
  366. static void
  367. freetty()
  368. {
  369.   brktty();
  370. #if defined(BSDJOBS) && !(defined(POSIX) || defined(SYSV))
  371.   if (DevTty >= 0)
  372.     {
  373.       close(DevTty);
  374.       DevTty = -1;
  375.     }
  376. #endif
  377.   close(0);
  378.   close(1);
  379.   close(2);
  380.   debug("did freetty\n");
  381. }
  382.  
  383. static void
  384. fgtty()
  385. {
  386. #ifdef BSDJOBS
  387.   int mypid;
  388.  
  389.   mypid = getpid();
  390.  
  391. # ifdef BSDI
  392.   setsid();
  393.   ioctl(0, TIOCSCTTY, 0);
  394. # endif /* BSDI */
  395.  
  396. # ifdef POSIX
  397.   if (tcsetpgrp(0, mypid))
  398.     {
  399.       debug1("fgtty: tcsetpgrp: %d\n", errno);
  400.       /* error is likely to have side-effects -- better to warn our user */
  401.       SendErrorMsg("fgtty: Could not set process group id in tty");
  402.     }
  403. # else
  404.   if (ioctl(0, TIOCSPGRP, &mypid) != 0)
  405.     debug1("fgtty: TIOSETPGRP: %d\n", errno);
  406.   /* posix setsid() in brktty() from freetty() already made us leader */
  407.   if (setpgrp(0, mypid))
  408.     debug1("fgtty: setpgrp: %d\n", errno);
  409. # endif /* POSIX */
  410. #endif /* BSDJOBS */
  411. }
  412.  
  413. #ifdef hpux
  414. /*
  415.  * hpux has berkeley signal semantics if we use sigvector,
  416.  * but not, if we use signal, so we define our own signal() routine.
  417.  * (jw)
  418.  */
  419. void (*signal(sig, func)) ()
  420. int sig;
  421. void (*func) ();
  422. {
  423.   struct sigvec osv, sv;
  424.  
  425.   sv.sv_handler = func;
  426.   sv.sv_mask = sigmask(sig);
  427.   sv.sv_flags = SV_BSDSIG;
  428.   if (sigvector(sig, &sv, &osv) < 0)
  429.     return (BADSIG);
  430.   return (osv.sv_handler);
  431. }
  432. #endif    /* hpux */
  433.  
  434. #ifndef USEBCOPY
  435. #ifdef bcopy
  436. #undef bcopy
  437. #endif
  438. void bcopy(s1, s2, len)
  439. register char *s1, *s2;
  440. register int len;
  441. {
  442.   if (s1 < s2 && s2 < s1 + len)
  443.     {
  444.       s1 += len;
  445.       s2 += len;
  446.       while (len-- > 0)
  447.     *--s2 = *--s1;
  448.     }
  449.   else
  450.     while (len-- > 0)
  451.       *s2++ = *s1++;
  452. }
  453. #endif    /* USEBCOPY */
  454.  
  455. void bclear(p, n)
  456. int n;
  457. char *p;
  458. {
  459.   bcopy(blank, p, n);
  460. }
  461.  
  462. static void
  463. closeallfiles()
  464. {
  465.   int f;
  466. #ifdef SVR4
  467.   struct rlimit rl;
  468.   
  469.   if ((getrlimit(RLIMIT_NOFILE, &rl) == 0) && rl.rlim_max != RLIM_INFINITY)
  470.     f = rl.rlim_max;
  471.   else
  472. #endif /* SVR4 */
  473. #if defined(SYSV) && !defined(ISC)
  474.   f = NOFILE;
  475. #else /* SYSV && !ISC */
  476.   f = getdtablesize();
  477. #endif /* SYSV && !ISC */
  478.   while (--f > 2)
  479.     close(f);
  480. }
  481.   
  482. static int InterruptPlease = 0;
  483.  
  484. void main(ac, av)
  485. int ac;
  486. char **av;
  487. {
  488.   register int n, len;
  489.   register struct win *p;
  490.   char *ap, *aka = NULL;
  491.   char *av0;
  492.   char socknamebuf[2 * MAXSTR];
  493.   int s = 0;
  494.   fd_set r, w, e;
  495.   int mflag = 0;
  496.   struct timeval tv;
  497.   int nsel;
  498.   char buf[IOSIZE], *bufp, *myname = (ac == 0) ? "screen" : av[0];
  499.   struct stat st;
  500.   int buflen, tmp;
  501. #ifdef _MODE_T            /* (jw) */
  502.   mode_t oumask;
  503. #else
  504.   int oumask;
  505. #endif
  506. #ifdef SYSV
  507.   struct utsname utsnam;
  508. #endif
  509.  
  510.   /*
  511.    *  First, close all unused descriptors
  512.    *  (otherwise, we might have problems with the select() call)
  513.    */
  514.   closeallfiles();
  515. #ifdef DEBUG
  516.   (void) mkdir("/tmp/debug", 0777);
  517.   if ((dfp = fopen("/tmp/debug/screen.front", "w")) == NULL)
  518.     dfp = stderr;
  519.   else
  520.     (void) chmod("/tmp/debug/screen.front", 0666);
  521. #endif
  522.   debug1("-- screen debug started %s\n", *av);
  523. #ifdef POSIX
  524.   debug("POSIX\n");
  525. #endif
  526. #ifdef TERMIO
  527.   debug("TERMIO\n");
  528. #endif
  529. #ifdef SYSV
  530.   debug("SYSV\n");
  531. #endif
  532. #ifdef NAMEDPIPE
  533.   debug("NAMEDPIPE\n");
  534. #endif
  535. #if defined(SIGWINCH) && defined(TIOCGWINSZ)
  536.   debug("Window changing enabled\n");
  537. #endif
  538. #ifdef NOREUID
  539.   debug("NOREUID\n");
  540. #endif
  541. #ifdef hpux
  542.   debug("hpux\n");
  543. #endif
  544. #ifdef USEBCOPY
  545.   debug("USEBCOPY\n");
  546. #endif
  547. #ifdef UTMPOK
  548.   debug("UTMPOK\n");
  549. #endif
  550. #ifdef NETHACK
  551.   debug("NETHACK\n");
  552. #endif
  553. #ifdef TERMINFO
  554.   debug("TERMINFO\n");
  555. #endif
  556. #ifdef NAME_MAX
  557.   debug1("NAME_MAX = %d\n", NAME_MAX);
  558. #endif
  559.  
  560.   BellString = SaveStr("Bell in window %");
  561.   VisualBellString = SaveStr("   Wuff,  Wuff!!  ");
  562.   ActivityString = SaveStr("Activity in window %");
  563.   BufferFile = SaveStr("/tmp/screen-exchange");
  564.   PowDetachString = 0;
  565.   default_histheight = DEFAULTHISTHEIGHT;
  566.   default_startup = (ac > 1) ? 0 : 1;
  567.   adaptflag = 0;
  568.   slowpaste = 0;
  569.   VBellWait = VBELLWAIT;
  570.   MsgWait = MSGWAIT;
  571.   MsgMinWait = MSGMINWAIT;
  572.   CompileKeys((char *)NULL, mark_key_tab);
  573.  
  574.   av0 = *av;
  575.   while (ac > 0)
  576.     {
  577.       ap = *++av;
  578.       if (--ac > 0 && *ap == '-')
  579.     {
  580.       switch (ap[1])
  581.         {
  582.         case 'a':
  583.           allflag = 1;
  584.           break;
  585.         case 'A':
  586.           adaptflag = 1;
  587.           break;
  588.         case 'c':
  589.           if (ap[2])
  590.         RcFileName = ap + 2;
  591.           else
  592.         {
  593.           if (--ac == 0)
  594.             exit_with_usage(myname);
  595.           RcFileName = *++av;
  596.         }
  597.           break;
  598.         case 'e':
  599.           if (ap[2])
  600.         ap += 2;
  601.           else
  602.         {
  603.           if (--ac == 0)
  604.             exit_with_usage(myname);
  605.           ap = *++av;
  606.         }
  607.           if (!ParseEscape(ap))
  608.         Msg(0, "Two characters are required with -e option.");
  609.           break;
  610.         case 'f':
  611.           switch (ap[2])
  612.         {
  613.         case 'n':
  614.         case '0':
  615.           default_flow = FLOW_NOW * 0;
  616.           break;
  617.         case 'y':
  618.         case '1':
  619.         case '\0':
  620.           default_flow = FLOW_NOW * 1;
  621.           break;
  622.         case 'a':
  623.           default_flow = FLOW_AUTOFLAG;
  624.           break;
  625.         default:
  626.           exit_with_usage(myname);
  627.         }
  628.           break;
  629.             case 'h':
  630.           if (ap[2])
  631.         default_histheight = atoi(ap + 2);
  632.           else
  633.         {
  634.           if (--ac == 0)
  635.             exit_with_usage(myname);
  636.           default_histheight = atoi(*++av);
  637.         }
  638.           if (default_histheight < 0)
  639.         default_histheight = 0;
  640.           break;
  641.         case 'i':
  642.           iflag = 1;
  643.           break;
  644.         case 't': /* title is a synonym for AkA */
  645.         case 'k':
  646.           if (ap[2])
  647.         aka = ap + 2;
  648.           else
  649.         {
  650.           if (--ac == 0)
  651.             exit_with_usage(myname);
  652.           aka = *++av;
  653.         }
  654.           break;
  655.         case 'l':
  656.           switch (ap[2])
  657.         {
  658.         case 'n':
  659.         case '0':
  660.           loginflag = 0;
  661.           break;
  662.         case 'y':
  663.         case '1':
  664.         case '\0':
  665.           loginflag = 1;
  666.           break;
  667.         case 's':
  668.         case 'i':
  669.           lsflag = 1;
  670.           break;
  671.         default:
  672.           exit_with_usage(myname);
  673.         }
  674.           break;
  675.         case 'w':
  676.           lsflag = 1;
  677.           wipeflag = 1;
  678.           break;
  679.         case 'L':
  680.           assume_LP = 1;
  681.           break;
  682.         case 'm':
  683.           mflag = 1;
  684.           break;
  685.         case 'O':
  686.           force_vt = 0;
  687.           break;
  688.         case 'T':
  689.               if (ap[2])
  690.         {
  691.           if (strlen(ap+2) < 20)
  692.                     strcpy(screenterm, ap + 2);
  693.         }
  694.               else
  695.                 {
  696.                   if (--ac == 0)
  697.                     exit_with_usage(myname);
  698.           if (strlen(*++av) < 20)
  699.                     strcpy(screenterm, *av);
  700.                 }
  701.               break;
  702.         case 'q':
  703.           quietflag = 1;
  704.           break;
  705.         case 'r':
  706.         case 'R':
  707.           if (ap[2])
  708.         {
  709.           SockName = ap + 2;
  710.           if (ac != 1)
  711.             exit_with_usage(myname);
  712.         }
  713.           else if (ac > 1 && *av[1] != '-')
  714.         {
  715.           SockName = *++av;
  716.           ac--;
  717.         }
  718.           rflag = (ap[1] == 'r') ? 1 : 2;
  719.           break;
  720. #ifdef REMOTE_DETACH
  721.         case 'd':
  722.           dflag = 1;
  723.           /* FALLTHRU */
  724.         case 'D':
  725.           if (!dflag)
  726.         dflag = 2;
  727.           if (ap[2])
  728.         SockName = ap + 2;
  729.           if (ac == 2)
  730.         {
  731.           if (*av[1] != '-')
  732.             {
  733.               SockName = *++av;
  734.               ac--;
  735.             }
  736.         }
  737.           break;
  738. #endif
  739.         case 's':
  740.           if (ap[2])
  741.         ShellProg = ap + 2;
  742.           else
  743.         {
  744.           if (--ac == 0)
  745.             exit_with_usage(myname);
  746.           ShellProg = *++av;
  747.         }
  748.           break;
  749.         default:
  750.           exit_with_usage(myname);
  751.         }
  752.     }
  753.       else
  754.     break;
  755.     }
  756.   real_uid = getuid();
  757.   real_gid = getgid();
  758.   eff_uid = geteuid();
  759.   eff_gid = getegid();
  760.   if (eff_uid != real_uid)
  761.     {        
  762.       /* if running with s-bit, we must install a special signal
  763.        * handler routine that resets the s-bit, so that we get a
  764.        * core file anyway.
  765.        */
  766.       signal(SIGBUS, CoreDump);
  767.       signal(SIGSEGV, CoreDump);
  768.     }
  769.   if (!ShellProg && (ShellProg = getenv("SHELL")) == 0)
  770.     ShellProg = DefaultShell;
  771.   ShellArgs[0] = ShellProg;
  772. #ifdef NETHACK
  773.   nethackflag = (getenv("NETHACKOPTIONS") != NULL);
  774. #endif
  775.   home = getenv("HOME");    /* may or may not return a result. jw. */
  776.   if ((LoginName = getlogin()) && LoginName[0] != '\0')
  777.     {
  778.       if ((ppp = getpwnam(LoginName)) != (struct passwd *) 0)
  779.     if (ppp->pw_uid != real_uid)
  780.       ppp = (struct passwd *) 0;
  781.     }
  782.   if (ppp == 0)
  783.     {
  784.       if ((ppp = getpwuid(real_uid)) == 0)
  785.         {
  786. #ifdef NETHACK
  787.           if (nethackflag)
  788.         Msg(0, "An alarm sounds through the dungeon...\nWarning, the kops are coming.");
  789.       else
  790. #endif
  791.       Msg(0, "getpwuid() can't identify your account!");
  792.       exit(1);
  793.         }
  794.       LoginName = ppp->pw_name;
  795.     }
  796.   if (home == 0 || *home == '\0')
  797.     home = ppp->pw_dir;
  798.   if (strlen(LoginName) > 20)
  799.     Msg(0, "LoginName too long - sorry.");
  800.   if (strlen(home) > MAXPATH - 25)
  801.     Msg(0, "$HOME too long - sorry.");
  802. #ifdef PASSWORD
  803.   strcpy(Password, ppp->pw_passwd);
  804. #endif
  805.  
  806.   /* ttyname implies isatty */
  807.   if (!(attach_tty = ttyname(0)))
  808.     {
  809. #ifdef NETHACK
  810.       if (nethackflag)
  811.     Msg(0, "You must play from a terminal.");
  812.       else
  813. #endif
  814.       Msg(0, "Must be connected to a terminal.");
  815.       exit(1);
  816.     }
  817.   if (strlen(attach_tty) >= MAXPATH)
  818.     Msg(0, "TtyName too long - sorry.");
  819.   if ((n = secopen(attach_tty, O_RDWR, 0)) < 0)
  820.     Msg(0, "Cannot open '%s' - please check.", attach_tty);
  821.   close(n);
  822.     
  823.   debug1("attach_tty is %s\n", attach_tty);
  824.   
  825. #ifdef _MODE_T
  826.   oumask = umask(0);        /* well, unsigned never fails? jw. */
  827. #else
  828.   if ((oumask = umask(0)) == -1)
  829.     Msg(errno, "Cannot change umask to zero");
  830. #endif
  831.   if ((SockDir = getenv("ISCREENDIR")) == NULL)
  832.     SockDir = getenv("SCREENDIR");
  833.   if (SockDir && strlen(SockDir) >= MAXPATH - 1)
  834.     Msg(0, "ridiculous long $(I)SCREENDIR - try again.");
  835. #ifndef SOCKDIR
  836.   if (SockDir == 0)
  837.     {
  838.       sprintf(SockPath, "%s/.iscreen", home);
  839.       SockDir = SockPath;
  840.     }
  841. #endif
  842.   if (SockDir)
  843.     {
  844.       if (access(SockDir, F_OK))
  845.     {
  846.       if (UserContext() > 0)
  847.         {
  848.           if (mkdir(SockDir, 0700))
  849.         UserReturn(0);
  850.           UserReturn(1);
  851.         }
  852.       if (UserStatus() <= 0)
  853.         Msg(0, "Cannot make directory '%s'", SockDir);
  854.     }
  855.       if (SockDir != SockPath)
  856.         strcpy(SockPath, SockDir);
  857.     }
  858. #ifdef SOCKDIR
  859.   else
  860.     {
  861.       SockDir = SOCKDIR;
  862.       if (stat(SockDir, &st))
  863.     {
  864.       if (mkdir(SockDir, eff_uid ? 0777 : 0755) == -1)
  865.         Msg(errno, "Cannot make directory '%s'", SockDir);
  866.     }
  867.       else
  868.     {
  869.           n = eff_uid ? 0777 : 0755;
  870.       if ((st.st_mode & 0777) != n)
  871.         Msg(0, "Directory '%s' must have mode %03o.", SockDir, n);
  872.     }
  873.       sprintf(SockPath, "%s/S-%s", SockDir, LoginName);
  874.       if (access(SockPath, F_OK))
  875.     {
  876.       if (mkdir(SockPath, 0700) == -1)
  877.         Msg(errno, "Cannot make directory '%s'", SockPath);
  878.       (void) chown(SockPath, real_uid, real_gid);
  879.     }
  880.     }
  881. #endif
  882.   if (stat(SockPath, &st) == -1)
  883.     {
  884.       Msg(errno, "Cannot access %s", SockPath);
  885.     }
  886.   else
  887.     {
  888. #ifdef _POSIX_SOURCE
  889.       if (S_ISDIR(st.st_mode) == 0)
  890. #else
  891.       if ((st.st_mode & S_IFMT) != S_IFDIR)
  892. #endif
  893.     Msg(0, "%s is not a directory.", SockPath);
  894.       if (st.st_uid != real_uid)
  895.     Msg(0, "You are not the owner of %s.", SockPath);
  896.       if ((st.st_mode & 0777) != 0700)
  897.     Msg(0, "Directory %s must have mode 700.", SockPath);
  898.     }
  899.   strcat(SockPath, "/");
  900.   SockNamePtr = SockPath + strlen(SockPath);
  901.   (void) umask(oumask);
  902. #if defined(SYSV) && !defined(ISC)
  903.   if (uname(&utsnam) == -1)
  904.     Msg(0, "uname() failed, errno = %d", errno);
  905.   else
  906.     {
  907.       strncpy(HostName, utsnam.nodename, MAXSTR);
  908.       HostName[(sizeof(utsnam.nodename) <= MAXSTR) ? 
  909.                sizeof(utsnam.nodename) : MAXSTR] = '\0';
  910.     }
  911. #else
  912.   (void) gethostname(HostName, MAXSTR);
  913. #endif
  914.   HostName[MAXSTR - 1] = '\0';
  915.   if ((ap = index(HostName, '.')) != NULL)
  916.     *ap = '\0';
  917.   GetTTY(0, &OldMode);
  918. #ifdef POSIX
  919.   ospeed = (short) cfgetospeed(&OldMode.tio);
  920. #else
  921. # ifndef TERMIO
  922.   ospeed = (short) OldMode.m_ttyb.sg_ospeed;
  923. # endif
  924. #endif
  925.   debug1("...setting extern short ospeed = %d\n", ospeed);
  926.  
  927.   if (lsflag)
  928.     {
  929.       int i;
  930.       i = FindSocket(0, (int *)NULL);
  931.       /* MakeClientSocket appended the last (Sock)Name there: */
  932.       *SockNamePtr = '\0';
  933.       if (i == 0)
  934.     {
  935. #ifdef NETHACK
  936.           if (nethackflag)
  937.         Msg(0, "This room is empty (%s)\n", SockPath);
  938.           else
  939. #endif /* NETHACK */
  940.           Msg(0, "No Sockets found in %s\n", SockPath);
  941.         }
  942.       else
  943.         Msg(0, "%d Socket%s in %s.\n", i, i > 1 ? "s" : "", SockPath);
  944.         /* NOTREACHED */
  945.     }
  946.   if (rflag)
  947.     {
  948.       debug("screen -r: - is there anybody out there?\n");
  949. #ifdef SHADOWPW
  950.       setspent();  /* open shadow file while we are still root */
  951. #endif /* SHADOWPW */
  952.       if (Attach(MSG_ATTACH))
  953.     {
  954.       Attacher();
  955.       /* NOTREACHED */
  956.     }
  957.       debug("screen -r: backend not responding -- still crying\n");
  958.     }
  959.   else if (dflag)
  960.     {
  961.       (void) Attach(MSG_DETACH);
  962.       DeadlyMsg = 0;
  963.       Msg(0, "[%s %sdetached.]\n", SockName, (dflag > 1 ? "power " : ""));
  964.       eexit(0);
  965.       /* NOTREACHED */
  966.     }
  967.   if (!mflag && (SockName = getenv("STY")) != 0 && *SockName != '\0')
  968.     {
  969.       setuid(real_uid);
  970.       setgid(real_gid);
  971.       s = MakeClientSocket(1, SockName);
  972.       if (ac == 0)
  973.     {
  974.       ac = 1;
  975.       av = ShellArgs;
  976.     }
  977.       av[ac] = aka;
  978.       SendCreateMsg(s, ac, av, allflag, default_flow, loginflag, default_histheight,
  979.             screenterm);
  980.       close(s);
  981.       exit(0);
  982.     }
  983. #if defined(BSDJOBS) && !(defined(POSIX) || defined(SYSV))
  984.   if ((DevTty = open("/dev/tty", O_RDWR | O_NDELAY)) == -1)
  985.     Msg(errno, "/dev/tty");
  986. #endif
  987.   switch (MasterPid = fork())
  988.     {
  989.     case -1:
  990.       Msg(errno, "fork");
  991.       /* NOTREACHED */
  992.     case 0:
  993.       break;
  994.     default:
  995.       sprintf(socknamebuf, "%d.%s.%s", MasterPid, stripdev(attach_tty),
  996.           HostName);
  997.       for (ap = socknamebuf; *ap; ap++)
  998.     if (*ap == '/')
  999.       *ap = '-';
  1000.       SockName = socknamebuf;
  1001. #ifdef SHADOWPW
  1002.       setspent();  /* open shadow file while we are still root */
  1003. #endif /* SHADOWPW */
  1004.       Attacher();
  1005.       /* NOTREACHED */
  1006.     }
  1007. #ifdef DEBUG
  1008.   if (dfp != stderr)
  1009.     fclose(dfp);
  1010.   if ((dfp = fopen("/tmp/debug/screen.back", "w")) == NULL)
  1011.     dfp = stderr;
  1012.   else
  1013.     (void) chmod("/tmp/debug/screen.back", 0666);
  1014. #endif
  1015.   debug("-- screen.back debug started\n");
  1016.   ap = av0 + strlen(av0) - 1;
  1017.   while (ap >= av0)
  1018.     {
  1019.       if (!strncmp("screen", ap, 6))
  1020.     {
  1021.       strncpy(ap, "SCREEN", 6); /* name this process "SCREEN-BACKEND" */
  1022.       break;
  1023.     }
  1024.       ap--;
  1025.     }
  1026.   if (ap < av0)
  1027.     *av0 = 'S';
  1028.  
  1029.   AttacherPid = getppid();
  1030.   sprintf(socknamebuf, "%d.%s.%s", getpid(), stripdev(attach_tty), HostName);
  1031.   for (ap = socknamebuf; *ap; ap++)
  1032.     if (*ap == '/')
  1033.       *ap = '-';
  1034.   SockName = socknamebuf;
  1035.   ServerSocket = s = MakeServerSocket();
  1036. #ifdef ETCSCREENRC
  1037.   if ((ap = getenv("SYSSCREENRC")) == NULL)
  1038.     StartRc(ETCSCREENRC);
  1039.   else
  1040.     StartRc(ap);
  1041. #endif
  1042.   StartRc(RcFileName);
  1043.   InitTermcap();
  1044.   InitTerm(0);
  1045.   MakeNewEnv();
  1046.   strcpy(display_tty, attach_tty);
  1047. #ifdef UTMPOK
  1048. # ifdef apollo
  1049.   ReInitUtmp();
  1050. # else
  1051.   InitUtmp();
  1052. # endif /* apollo */
  1053. #endif /* UTMPOK */
  1054.   signal(SIGHUP, SigHup);
  1055.   signal(SIGINT, Finit);
  1056.   signal(SIGQUIT, Finit);
  1057.   signal(SIGTERM, Finit);
  1058. #ifdef BSDJOBS
  1059.   signal(SIGTTIN, SIG_IGN);
  1060.   signal(SIGTTOU, SIG_IGN);
  1061. #endif
  1062.   InitKeytab();
  1063. #ifdef ETCSCREENRC
  1064.   if ((ap = getenv("SYSSCREENRC")) == NULL)
  1065.     FinishRc(ETCSCREENRC);
  1066.   else
  1067.     FinishRc(ap);
  1068. #endif
  1069.   FinishRc(RcFileName);
  1070.  
  1071.   /* Note: SetMode must be called _after_ FinishRc (flow is set there).
  1072.    */
  1073.   SetMode(&OldMode, &NewMode);
  1074.   SetTTY(0, &NewMode);
  1075.   if (loginflag == -1)
  1076.       loginflag = LOGINDEFAULT;
  1077.   if (ac == 0)
  1078.     {
  1079.       ac = 1;
  1080.       av = ShellArgs;
  1081.       if (!aka)
  1082.     aka = shellaka;
  1083.     }
  1084.   if (!HasWindow)
  1085.     {
  1086.       debug("We open one default window, as screenrc did not specify one.\n");
  1087.       if (MakeWindow(aka, av, allflag, default_flow, 0, (char *)0, loginflag, -1, (char *)0) == -1)
  1088.     {
  1089.       Finit(1);
  1090.       /* NOTREACHED */
  1091.     }
  1092.     }
  1093.   if (default_startup)
  1094.     display_copyright();
  1095. #ifdef SYSV
  1096.   signal(SIGCLD, SigChld);
  1097. #else
  1098.   signal(SIGCHLD, SigChld);
  1099. #endif
  1100.   signal(SIGINT, SigInt);
  1101.   tv.tv_usec = 0;
  1102.   if (rflag == 2)
  1103.     {
  1104. #ifdef NETHACK
  1105.       if (nethackflag)
  1106.         Msg(0, "I can't seem to find a... Hey, wait a minute!  Here comes a screen now.");
  1107.       else
  1108. #endif
  1109.       Msg(0, "New screen...");
  1110.       rflag = 0;
  1111.     }
  1112.   brktty();
  1113.   for (;;)
  1114.     {
  1115.       /*
  1116.        * check to see if message line should be removed
  1117.        */
  1118.       if (status)
  1119.     {
  1120.       int time_left;
  1121.  
  1122.       debug("checking status...\n");
  1123.       time_left = TimeDisplayed + (BellDisplayed ? VBellWait : MsgWait) - time((time_t *)0);
  1124.       if (time_left > 0)
  1125.         {
  1126.           tv.tv_sec = time_left;
  1127.           debug(" not yet.\n");
  1128.         }
  1129.       else
  1130.         {
  1131.           debug(" removing now.\n");
  1132.           RemoveStatus();
  1133.         }
  1134.     }
  1135.       /*
  1136.        * check for I/O on all available I/O descriptors
  1137.        */
  1138.       FD_ZERO(&r);
  1139.       FD_ZERO(&w);
  1140.       FD_ZERO(&e);
  1141.       if (inbuf_ct > 0)
  1142.     for (n = 0; n < MAXWIN; n++)
  1143. #ifdef COPY_PASTE        /* wrong here? jw. */
  1144.       if (inlen[n] > 0 || (pastelen > 0 && n == ForeNum))
  1145. #else
  1146.       if (inlen[n] > 0)
  1147. #endif
  1148.         FD_SET(wtab[n]->ptyfd, &w);
  1149.       if (!Detached)
  1150.     FD_SET(0, &r);
  1151.       for (n = WinList; n != -1; n = p->WinLink)
  1152.     {
  1153.       p = wtab[n];
  1154.       if (p->active && status && !BellDisplayed && !HS)
  1155.         continue;
  1156.       if (p->outlen > 0)
  1157.         continue;
  1158.       if (in_ovl && ovl_blockfore && n == ForeNum)
  1159.         continue;
  1160.       FD_SET(p->ptyfd, &r);
  1161.     }
  1162.       FD_SET(s, &r);
  1163.       (void) fflush(stdout);
  1164.       if (GotSignal && !status)
  1165.     {
  1166.       SigHandler();
  1167.       continue;
  1168.     }
  1169.       if ((nsel = select(FD_SETSIZE, &r, &w, &e, (status) ? &tv : (struct timeval *) 0)) < 0)
  1170.     {
  1171.       debug1("Bad select - errno %d\n", errno);
  1172.       if (errno != EINTR)
  1173.         {
  1174.           perror("select");
  1175.           Finit(1);
  1176.         }
  1177.       else
  1178.         {
  1179.           errno = 0;
  1180.           if ((!GotSignal || status) && !InterruptPlease)
  1181.             continue;
  1182.         }
  1183.     }
  1184.       if (InterruptPlease)
  1185.     {
  1186.       char buf[1];
  1187.  
  1188.       debug("Backend received interrupt\n");
  1189.       *buf = intrc;
  1190.       write(wtab[ForeNum]->ptyfd, buf, 1);
  1191.       debug1("Backend wrote interrupt to %d\n", ForeNum);
  1192.       InterruptPlease = 0;
  1193.  
  1194.       continue;
  1195.     }
  1196.       if (GotSignal && !status)
  1197.     {
  1198.       SigHandler();
  1199.       continue;
  1200.     }
  1201.       /* Process a client connect attempt and message */
  1202.       if (nsel && FD_ISSET(s, &r))
  1203.     {
  1204.           nsel--;
  1205.       if (!HS)
  1206.         RemoveStatus();
  1207.       if (in_ovl)
  1208.         {
  1209.           SetOvlCurr();
  1210.           (*ovl_process)(0, 0); /* We have to abort first!! */
  1211.           CheckScreenSize(1); /* Change fore */
  1212.           DeadlyMsg = 0;
  1213. #ifdef NETHACK
  1214.               if (nethackflag)
  1215.             Msg(0, "KAABLAMM!!!  You triggered a land mine!");
  1216.               else
  1217. #endif
  1218.           Msg(0, "Aborted because of window change or message.");
  1219.         }
  1220.       else
  1221.         CheckScreenSize(1); /* Change fore */
  1222.       ReceiveMsg(s);
  1223.       continue;
  1224.     }
  1225.       /*
  1226.        * Write the stored user input to the window descriptors first.
  1227.        * We do not want to choke, if he types fast.
  1228.        */
  1229.       if (nsel && inbuf_ct > 0)
  1230.     {
  1231.       for (n = 0; n < MAXWIN ; n++)
  1232.         {
  1233.           if (inlen[n] <= 0)
  1234.         continue;
  1235.           tmp = wtab[n]->ptyfd;
  1236.               if (FD_ISSET(tmp, &w))
  1237.                 {
  1238.           if ((len = write(tmp, inbuf[n], inlen[n])) > 0)
  1239.             {
  1240.               if ((inlen[n] -= len) == 0)
  1241.               inbuf_ct--;
  1242.               bcopy(inbuf[n] + len, inbuf[n], inlen[n]);
  1243.             }
  1244.           if (--nsel == 0)
  1245.             break;
  1246.         }
  1247.         }
  1248.     }
  1249.       /* Read, process, and store the user input */
  1250.       if (nsel && FD_ISSET(0, &r))
  1251.     {
  1252.           nsel--;
  1253.       if (!HS)
  1254.         RemoveStatus();
  1255.       if (ESCseen)
  1256.         {
  1257.           buf[0] = Esc;
  1258.           buflen = read(0, buf + 1, IOSIZE - 1) + 1;
  1259.           ESCseen = 0;
  1260.         }
  1261.       else
  1262.         buflen = read(0, buf, IOSIZE);
  1263.       if (buflen < 0)
  1264.         {
  1265.           debug1("Read error: %d - SigHup()ing!\n", errno);
  1266.           SigHup(SIGARG);
  1267.           continue;
  1268.         }
  1269.       if (buflen == 0)
  1270.         {
  1271.           debug("Found EOF - SigHup()ing!\n");
  1272.           SigHup(SIGARG);
  1273.           continue;
  1274.         }
  1275.       bufp = buf;
  1276.           if (in_ovl)
  1277.         {
  1278.           SetOvlCurr();
  1279.           (*ovl_process)(&bufp, &buflen);
  1280.         }
  1281.       while (buflen > 0)
  1282.         {
  1283.           n = ForeNum;
  1284.           len = inlen[n];
  1285.           bufp = ProcessInput(bufp, &buflen, inbuf[n], &inlen[n],
  1286.                   sizeof *inbuf);
  1287.           if (inlen[n] > 0 && len == 0)
  1288.         inbuf_ct++;
  1289.         }
  1290.       if (inbuf_ct > 0)
  1291.         continue;
  1292.     }
  1293.       if (GotSignal && !status)
  1294.     {
  1295.       SigHandler();
  1296.       continue;
  1297.     }
  1298. #ifdef COPY_PASTE
  1299.       /* Write the copybuffer contents first, if any. jw. */
  1300.       if (pastelen > 0)
  1301.     {
  1302.       n = ForeNum;
  1303.       debug1("writing pastebuffer (%d)\n", pastelen);
  1304.       tmp = wtab[n]->ptyfd;
  1305.       if (            /* FD_ISSET(tmp, &w) && */
  1306.           (len = write(tmp, pastebuffer,
  1307.                pastelen > IOSIZE ? IOSIZE : pastelen)) > 0)
  1308.         {
  1309.           pastebuffer += len;
  1310.           pastelen -= len;
  1311.           debug1("%d bytes pasted\n", len);
  1312.           if (slowpaste > 0)
  1313.         {
  1314.           struct timeval t;
  1315.  
  1316.                   debug1("slowpaste %d\n", slowpaste);
  1317.           t.tv_usec = (long) (slowpaste * 1000);
  1318.           t.tv_sec = 0;
  1319.           select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);
  1320.         }
  1321.           else
  1322.             continue;
  1323.         }
  1324.       /* 
  1325.        * We could not paste? Let's see if the pty did echo the lot.
  1326.        * Then continue by processing some pty output.
  1327.        */
  1328.     }
  1329. #endif
  1330.       if (GotSignal && !status)
  1331.     {
  1332.       SigHandler();
  1333.       continue;
  1334.     }
  1335.       /* Read and process the output from the window descriptors */
  1336.       for (n = WinList; n != -1; n = p->WinLink)
  1337.     {
  1338.       p = wtab[n];
  1339.       if (in_ovl && ovl_blockfore && n == ForeNum)
  1340.         continue;
  1341.       if (p->outlen)
  1342.         WriteString(p, p->outbuf, p->outlen);
  1343.       else if (nsel && FD_ISSET(p->ptyfd, &r))
  1344.         {
  1345.           nsel--;
  1346.           if ((len = read(p->ptyfd, buf, IOSIZE)) == -1)
  1347.         {
  1348. #ifdef EWOULDBLOCK
  1349.           if (errno == EWOULDBLOCK)
  1350.             len = 0;
  1351. #endif
  1352.         }
  1353. #if defined(TIOCPKT) && !defined(sgi)
  1354.           if (buf[0])
  1355.         {
  1356.           debug1("PAKET %x\n", buf[0]);
  1357.           if (buf[0] & TIOCPKT_NOSTOP)
  1358.             {
  1359.               NewAutoFlow(p, 0);
  1360.             }
  1361.           if (buf[0] & TIOCPKT_DOSTOP)
  1362.             {
  1363.               NewAutoFlow(p, 1);
  1364.             }
  1365.         }
  1366.           if (len > 1)
  1367.         WriteString(p, buf + 1, len - 1);
  1368. #else /* TIOCPKT && !sgi */
  1369.           if (len > 0)
  1370.         WriteString(p, buf, len);
  1371. #endif /* TIOCPKT && !sgi */
  1372.         }
  1373.       if (p->bell == BELL_ON)
  1374.         {
  1375.           p->bell = BELL_DONE;
  1376.           Msg(0, MakeWinMsg(BellString, n));
  1377.           if (p->monitor == MON_FOUND)
  1378.         p->monitor = MON_DONE;
  1379.         }
  1380.       else if (p->bell == BELL_VISUAL)
  1381.         {
  1382.           if (!BellDisplayed)
  1383.         {
  1384.           p->bell = BELL_DONE;
  1385.           Msg(0, VisualBellString);
  1386.           BellDisplayed = 1;
  1387.         }
  1388.         }
  1389.       else if (p->monitor == MON_FOUND)
  1390.         {
  1391.           p->monitor = MON_DONE;
  1392.           Msg(0, MakeWinMsg(ActivityString, n));
  1393.         }
  1394.     }
  1395.       if (GotSignal && !status)
  1396.     SigHandler();
  1397. #ifdef DEBUG
  1398.       if (nsel)
  1399.     debug1("Left over nsel: %d\n", nsel);
  1400. #endif
  1401.     }
  1402.   /* NOTREACHED */
  1403. }
  1404.  
  1405. static void SigHandler()
  1406. {
  1407.   struct stat st;
  1408.   while (GotSignal)
  1409.     {
  1410.       GotSignal = 0;
  1411.       DoWait();
  1412. #ifdef SYSV
  1413.       signal(SIGCLD, SigChld);
  1414. #endif
  1415.     }
  1416.   if (stat(SockPath, &st) == -1)
  1417.     {
  1418.       debug1("SigHandler: Yuck! cannot stat '%s'\n", SockPath);
  1419.       if (!RecoverSocket())
  1420.     {
  1421.       debug("SCREEN cannot recover from corrupt Socket, bye\n");
  1422.       Finit(1);
  1423.     }
  1424.       else
  1425.     debug1("'%s' reconstructed\n", SockPath);
  1426.     }
  1427.   else
  1428.     debug2("SigHandler: stat '%s' o.k. (%03o)\n", SockPath, st.st_mode);
  1429. }
  1430.  
  1431. #ifdef DEBUG
  1432. int FEpanic;
  1433.  
  1434. sig_t FEChld(SIGDEFARG)
  1435. {
  1436.   FEpanic=1;
  1437. #ifndef SIGVOID
  1438.   return((sig_t) 0);
  1439. #endif
  1440. }
  1441. #endif
  1442.  
  1443. static sig_t SigChld(SIGDEFARG)
  1444. {
  1445.   debug("SigChld()\n");
  1446.   GotSignal = 1;
  1447. #ifndef SIGVOID
  1448.   return((sig_t) 0);
  1449. #endif
  1450. }
  1451.  
  1452. sig_t SigHup(SIGDEFARG)
  1453. {
  1454.   debug("SigHup()\n");
  1455.   if (auto_detach)
  1456.     Detach(D_DETACH);
  1457.   else
  1458.     Finit(0);
  1459. #ifndef SIGVOID
  1460.   return((sig_t) 0);
  1461. #endif
  1462. }
  1463.  
  1464. /*
  1465.  * the frontend's Interrupt handler
  1466.  * we forward SIGINT to the backend
  1467.  */
  1468. static sig_t 
  1469. AttacherSigInt(SIGDEFARG)
  1470. {
  1471.   Kill(MasterPid, SIGINT);
  1472.   signal(SIGINT, AttacherSigInt);
  1473. # ifndef SIGVOID
  1474.   return (sig_t) 0;
  1475. # endif
  1476. }
  1477.  
  1478.  
  1479. /* 
  1480.  * the backend's Interrupt handler
  1481.  * we cannot insert the intrc directly, as we never know
  1482.  * if fore and ForeNum are valid.
  1483.  */
  1484. static sig_t SigInt(SIGDEFARG)
  1485. {
  1486. #if HAZARDOUS
  1487.   char buf[1];
  1488.  
  1489.   debug("SigInt()\n");
  1490.   *buf = (char) intrc;
  1491.   inlen[ForeNum] = 0;
  1492.   if (fore && !in_ovl)
  1493.     write(fore->ptyfd, buf, 1);
  1494. #else
  1495.   debug("SigInt() careful\n");
  1496.   InterruptPlease = 1;
  1497.   signal(SIGINT, SigInt);
  1498. #endif
  1499. #ifndef SIGVOID
  1500.   return((sig_t) 0);
  1501. #endif
  1502. }
  1503.  
  1504. static sig_t CoreDump(sig)
  1505. int sig;
  1506. {
  1507.   setgid(getgid());
  1508.   setuid(getuid());
  1509.   unlink("core");
  1510.   fprintf(stderr, "\r\n[screen caught signal %d.%s]\r\n", sig,
  1511. #ifdef SHADOWPW
  1512.           ""
  1513. #else /* SHADOWPW */
  1514.           " (core dumped)"
  1515. #endif /* SHADOWPW */
  1516.           );
  1517.   fflush(stderr);
  1518.   Kill(AttacherPid, SIG_BYE);
  1519. #ifdef SHADOWPW
  1520.   eexit(sig);
  1521. #else /* SHADOWPW */
  1522.   abort();
  1523. #endif /* SHADOWPW */
  1524. #ifndef SIGVOID
  1525.   return((sig_t) 0);
  1526. #endif
  1527. }
  1528.  
  1529. static void DoWait()
  1530. {
  1531.   register int n, next, pid;
  1532. #ifdef BSDWAIT
  1533.   union wait wstat;
  1534. #else
  1535.   int wstat;
  1536. #endif
  1537.  
  1538. #ifdef BSDJOBS
  1539. # ifndef BSDWAIT
  1540.   while ((pid = waitpid(-1, &wstat, WNOHANG | WUNTRACED)) > 0)
  1541. # else
  1542.   while ((pid = wait3(&wstat, WNOHANG | WUNTRACED, (struct rusage *) 0)) > 0)
  1543. # endif
  1544. #else    /* BSDJOBS */
  1545.   while ((pid = wait(&wstat)) < 0)
  1546.     if (errno != EINTR)
  1547.       break;
  1548.   if (pid >= 0)
  1549. #endif    /* BSDJOBS */
  1550.     {
  1551.       for (n = WinList; n != -1; n = next)
  1552.     {
  1553.       next = wtab[n]->WinLink;
  1554.       if (pid == wtab[n]->wpid)
  1555.         {
  1556. #ifdef BSDJOBS
  1557.           if (WIFSTOPPED(wstat))
  1558.         {
  1559. # ifdef NETHACK    
  1560.                   if (nethackflag)
  1561.             Msg(0, "You regain consciousness.");
  1562.           else
  1563. # endif /* NETHACK */
  1564.           Msg(0, "Child has been stopped, restarting.");
  1565.           debug1("WIFSTOPPED: %d SIGCONT\n", wtab[n]->wpid);
  1566.           if (killpg(wtab[n]->wpid, SIGCONT))
  1567.             kill(wtab[n]->wpid, SIGCONT);
  1568.         }
  1569.           else
  1570. #endif
  1571.         KillWindow(n);
  1572.         }
  1573.     }
  1574.     }
  1575. }
  1576.  
  1577. void KillWindow(n)
  1578. int n;
  1579. {
  1580.   register int i;
  1581.   /*
  1582.    * Remove window from linked list.
  1583.    */
  1584.   if (n == WinList)    /* WinList = ForeNum */
  1585.     {
  1586.       RemoveStatus();
  1587.       WinList = fore->WinLink;
  1588.       fore = 0;
  1589.     }
  1590.   else
  1591.     {
  1592.       i = WinList;
  1593.       while (wtab[i]->WinLink != n)
  1594.     i = wtab[i]->WinLink;
  1595.       wtab[i]->WinLink = wtab[n]->WinLink;
  1596.     }
  1597.   FreeWindow(wtab[n]);
  1598.   wtab[n] = 0;
  1599.   if (inlen[n] > 0)
  1600.     {
  1601.       inlen[n] = 0;
  1602.       inbuf_ct--;
  1603.     }
  1604.   /*
  1605.    * If the foreground window disappeared check the head of the linked list
  1606.    * of windows for the most recently used window. If no window is alive at
  1607.    * all, exit.
  1608.    */
  1609.   if (WinList == -1)
  1610.     Finit(0);
  1611.   if (!fore)
  1612.     SwitchWindow(WinList);
  1613. }
  1614.  
  1615. static sig_t Finit(i)
  1616. int i;
  1617. {
  1618.   register int n, next;
  1619.  
  1620. #ifdef SYSV
  1621.   signal(SIGCLD, SIG_IGN);
  1622. #else
  1623.   signal(SIGCHLD, SIG_IGN);
  1624. #endif
  1625.   signal(SIGHUP, SIG_IGN);
  1626.   debug1("Finit(%d);\n", i);
  1627.   for (n = WinList; n != -1; n = next)
  1628.     {
  1629.       next = wtab[n]->WinLink;
  1630.       FreeWindow(wtab[n]);
  1631.     }
  1632.   FinitTerm();
  1633.   SetTTY(0, &OldMode);
  1634. #ifdef UTMPOK
  1635.   RestoreLoginSlot();
  1636. #endif
  1637.   printf("\n[screen is terminating]\n");
  1638.   freetty();
  1639.   if (ServerSocket != -1)
  1640.     {
  1641.       debug1("we unlink(%s)\n", SockPath);
  1642.       (void) unlink(SockPath);
  1643.     }
  1644.   Kill(AttacherPid, SIG_BYE);
  1645.   exit(i);
  1646. #ifndef SIGVOID
  1647.   return((sig_t) 0);
  1648. #endif
  1649. }
  1650.  
  1651. void
  1652. eexit(e)
  1653. int e;
  1654. {
  1655.   if (ServerSocket != -1)
  1656.     {
  1657.       debug1("we unlink(%s)\n", SockPath);
  1658.       (void) unlink(SockPath);
  1659.     }
  1660.   exit(e);
  1661. }
  1662.  
  1663. static void InitKeytab()
  1664. {
  1665.   register unsigned int i;
  1666.  
  1667.   for (i = 0; i < sizeof(ktab)/sizeof(*ktab); i++)
  1668.     ktab[i].type = KEY_IGNORE;
  1669.  
  1670.   ktab['h'].type = ktab[Ctrl('h')].type = KEY_HARDCOPY;
  1671. #ifdef BSDJOBS
  1672.   ktab['z'].type = ktab[Ctrl('z')].type = KEY_SUSPEND;
  1673. #endif
  1674.   ktab['c'].type = ktab[Ctrl('c')].type = KEY_SHELL;
  1675.   ktab[' '].type = ktab[Ctrl(' ')].type =
  1676.     ktab['n'].type = ktab[Ctrl('n')].type = KEY_NEXT;
  1677.   ktab['-'].type = ktab['p'].type = ktab[Ctrl('p')].type = KEY_PREV;
  1678.   ktab['k'].type = ktab[Ctrl('k')].type = KEY_KILL;
  1679.   ktab['l'].type = ktab[Ctrl('l')].type = KEY_REDISPLAY;
  1680.   ktab['w'].type = ktab[Ctrl('w')].type = KEY_WINDOWS;
  1681.   ktab['v'].type = ktab[Ctrl('v')].type = KEY_VERSION;
  1682.   ktab['q'].type = ktab[Ctrl('q')].type = KEY_XON;
  1683.   ktab['s'].type = ktab[Ctrl('s')].type = KEY_XOFF;
  1684.   ktab['t'].type = ktab[Ctrl('t')].type = KEY_TIME;
  1685.   ktab['i'].type = ktab[Ctrl('i')].type = KEY_INFO;
  1686.   ktab['m'].type = ktab[Ctrl('m')].type = KEY_LASTMSG;
  1687.   ktab['A'].type = KEY_AKA, ktab['A'].args = NULL;
  1688.   ktab['L'].type = KEY_LOGIN;
  1689.   ktab[','].type = KEY_LICENSE;
  1690.   ktab['W'].type = KEY_WIDTH;
  1691.   ktab['.'].type = KEY_TERMCAP;
  1692.   ktab[Ctrl('\\')].type = KEY_QUIT;
  1693.   ktab['d'].type = ktab[Ctrl('d')].type = KEY_DETACH;
  1694.   ktab['r'].type = ktab[Ctrl('r')].type = KEY_WRAP;
  1695.   ktab['f'].type = ktab[Ctrl('f')].type = KEY_FLOW;
  1696.   ktab['C'].type = KEY_CLEAR;
  1697.   ktab['Z'].type = KEY_RESET;
  1698.   ktab['H'].type = KEY_LOGTOGGLE;
  1699.   if (Esc != MetaEsc)
  1700.     ktab[Esc].type = KEY_OTHER;
  1701.   else
  1702.     ktab[Esc].type = KEY_IGNORE;
  1703.   ktab['M'].type = KEY_MONITOR;
  1704.   ktab['?'].type = KEY_HELP;
  1705.   for (i = 0; i <= 9; i++)
  1706.     ktab['0' + i].type = (enum keytype) (i + (int)KEY_0);
  1707.   ktab[Ctrl('G')].type = KEY_VBELL;
  1708.   ktab[':'].type = KEY_COLON;
  1709. #ifdef COPY_PASTE
  1710.   ktab['['].type = ktab[Ctrl('[')].type = KEY_COPY;
  1711.   ktab[']'].type = ktab[Ctrl(']')].type = KEY_PASTE;
  1712.   ktab['{'].type = KEY_HISTORY;
  1713.   ktab['}'].type = KEY_HISTNEXT;
  1714.   ktab['>'].type = KEY_WRITE_BUFFER;
  1715.   ktab['<'].type = KEY_READ_BUFFER;
  1716.   ktab['='].type = KEY_REMOVE_BUFFERS;
  1717. #endif
  1718. #ifdef POW_DETACH
  1719.   ktab['D'].type = KEY_POW_DETACH;
  1720. #endif
  1721. #ifdef LOCK
  1722.   ktab['x'].type = ktab[Ctrl('x')].type = KEY_LOCK;
  1723. #endif
  1724. }
  1725.  
  1726. /*
  1727.  * this is a braindamaged hack: if (obuf == NULL) then we provided
  1728.  * a key_type as a second char in ibuf. not a key.
  1729.  */
  1730. char *ProcessInput(ibuf, pilen, obuf, polen, obuf_size)
  1731. char *ibuf, *obuf;
  1732. register int *pilen, *polen, obuf_size;
  1733. {
  1734.   register int n;
  1735.   register enum keytype k;
  1736.   register char *s, *p;
  1737.   char buf[2];
  1738.   int newwidth;
  1739.  
  1740.   if (!obuf)
  1741.     obuf_size = 0;
  1742.  
  1743.   for (s = ibuf, p = obuf + *polen; *pilen > 0; --*pilen, s++)
  1744.     {
  1745.       if (*s == Esc)
  1746.     {
  1747.       debug2("'%c %c ", s[0], s[1]);
  1748.       debug2("%c %c' ", s[2], s[3]);
  1749.       if (*pilen > 1)
  1750.         {
  1751.           --*pilen;
  1752.           s++;
  1753. #if defined(GOULD_NP1)
  1754.           k = (obuf)?(ktab[*s].type):(enum keytype)(int)(*s);
  1755. #else
  1756.           k = (obuf)?(ktab[*s].type):(enum keytype)(*s);
  1757. #endif
  1758.           debug2("Processinput C-A %02x '%c' ", k, k);
  1759.           debug1("%s\n", (obuf)?"std":"NOOBUF");
  1760.           if (*s == MetaEsc)
  1761.         {
  1762.           if (*polen < obuf_size)
  1763.             {
  1764.               *p++ = Esc;
  1765.               ++*polen;
  1766.             }
  1767.         }
  1768.           else if ((int)k >= (int)KEY_0 && (int)k <= (int)KEY_9)
  1769.         SwitchWindow((int)k - (int)KEY_0);
  1770.           else
  1771.         switch (k)
  1772.           {
  1773.           case KEY_TERMCAP:
  1774.             WriteFile(DUMP_TERMCAP);
  1775.             break;
  1776.           case KEY_HARDCOPY:
  1777.             WriteFile(DUMP_HARDCOPY);
  1778.             break;
  1779.           case KEY_LOGTOGGLE:
  1780.             LogToggle();
  1781.             break;
  1782. #ifdef BSDJOBS
  1783.           case KEY_SUSPEND:
  1784.             *pilen = 0;
  1785.             Detach(D_STOP);
  1786.             break;
  1787. #endif
  1788.           case KEY_SHELL:
  1789.             debug("calling MakeWindow with shell\n");
  1790.             MakeWindow(shellaka, ShellArgs, allflag, default_flow,
  1791.                    0, (char *) 0, loginflag, -1, (char *)0);
  1792.             break;
  1793.           case KEY_NEXT:
  1794.             if (MoreWindows())
  1795.               SwitchWindow(NextWindow());
  1796.             break;
  1797.           case KEY_PREV:
  1798.             if (MoreWindows())
  1799.               SwitchWindow(PreviousWindow());
  1800.             break;
  1801.           case KEY_KILL:
  1802.             KillWindow(n = ForeNum);
  1803. #ifdef NETHACK
  1804.                   if (nethackflag)
  1805.               Msg(0, "You destroy poor window %d", n);
  1806. #endif
  1807.             break;
  1808.           case KEY_QUIT:
  1809.             Finit(0);
  1810.             /* NOTREACHED */
  1811.           case KEY_DETACH:
  1812.             *pilen = 0;
  1813.             Detach(D_DETACH);
  1814.             break;
  1815. #ifdef POW_DETACH
  1816.           case KEY_POW_DETACH:
  1817.             *pilen = 0;
  1818.             if (obuf)
  1819.               {
  1820.             buf[0] = *s;
  1821.             buf[1] = '\0';
  1822.             Msg(0, buf);
  1823.             read(0, buf, 1);
  1824.             if (*buf != *s)
  1825.               {
  1826.                 write(1, "\007", 1);
  1827.                 RemoveStatus();
  1828. #ifdef NETHACK
  1829.                 if (nethackflag)
  1830.                    Msg(0, "The blast of disintegration whizzes by you!");
  1831. #endif
  1832.                 break;
  1833.               }
  1834.               }
  1835.             Detach(D_POWER); /* detach and kill Attacher's
  1836.                       * parent     */
  1837.             break;
  1838. #endif
  1839.           case KEY_REDISPLAY:
  1840.             Activate(0);
  1841.             break;
  1842.           case KEY_WINDOWS:
  1843.             ShowWindows();
  1844.             break;
  1845.           case KEY_VERSION:
  1846.             Msg(0, "screen %d.%.2d.%.2d%s (%s) %s", REV, VERS,
  1847.                 PATCHLEVEL, STATE, ORIGIN, DATE);
  1848.             break;
  1849.           case KEY_TIME:
  1850.             ShowTime();
  1851.             break;
  1852.           case KEY_INFO:
  1853.             ShowInfo();
  1854.             break;
  1855.           case KEY_OTHER:
  1856.             if (MoreWindows())
  1857.               SwitchWindow(fore->WinLink);
  1858.             break;
  1859.           case KEY_XON:
  1860.             if (*polen < obuf_size)
  1861.               {
  1862.             *p++ = Ctrl('q');
  1863.             ++*polen;
  1864.               }
  1865.             break;
  1866.           case KEY_XOFF:
  1867.             if (*polen < obuf_size)
  1868.               {
  1869.             *p++ = Ctrl('s');
  1870.             ++*polen;
  1871.               }
  1872.             break;
  1873. #ifdef LOCK
  1874.           case KEY_LOCK:
  1875.             Detach(D_LOCK); /* do it micha's way */
  1876.             break;
  1877. #endif
  1878.           case KEY_WIDTH:
  1879.             if (Z0 || WS)
  1880.               {
  1881.             if (fore->width == Z0width)
  1882.               newwidth = Z1width;
  1883.             else if (fore->width == Z1width)
  1884.               newwidth = Z0width;
  1885.             else if (fore->width > (Z0width+Z1width)/2)
  1886.               newwidth = Z0width;
  1887.             else
  1888.               newwidth = Z1width;
  1889.             ChangeWindowSize(fore, newwidth, fore->height);
  1890.             Activate(fore->norefresh);
  1891.               }
  1892.             else
  1893.               Msg(0, "Your termcap does not specify how to change the terminal's width.");
  1894.             break;
  1895.           case KEY_LOGIN:
  1896.             SlotToggle(0);
  1897.             break;
  1898.           case KEY_AKA:
  1899.             if (!ktab[*s].args)
  1900.               InputAKA();
  1901.             else
  1902.               strncpy(fore->cmd + fore->akapos, ktab[*s].args[0], 20);
  1903.             break;
  1904.           case KEY_COLON:
  1905.             InputColon();
  1906.             break;
  1907.           case KEY_LASTMSG:
  1908.             Msg(0, "%s", LastMsg);
  1909.             break;
  1910.           case KEY_SET:
  1911.             DoSet(ktab[*s].args);
  1912.             break;
  1913.           case KEY_SCREEN:
  1914.             debug3("KEY_SCREEN DoSc(, ktab[%d].args(='%s','%s')...)\n",
  1915.                *s, ktab[*s].args[0], ktab[*s].args[1]);
  1916.             DoScreen("key", ktab[*s].args);
  1917.             break;
  1918.           case KEY_CREATE:
  1919.             debug2("KEY_CREATE MaWi(0, ktab[%d].args(='%s')...)\n",
  1920.                *s, ktab[*s].args);
  1921.             MakeWindow((char *) 0, ktab[*s].args, allflag, default_flow, 0, (char *) 0, loginflag, -1, (char *)0);
  1922.             break;
  1923.           case KEY_WRAP:
  1924.             fore->wrap = !fore->wrap;
  1925.             Msg(0, "%cwrap", fore->wrap ? '+' : '-');
  1926.             break;
  1927.           case KEY_FLOW:
  1928.             if (fore->flow & FLOW_AUTOFLAG)
  1929.               fore->flow = (fore->flow & FLOW_AUTO) | FLOW_NOW;
  1930.             else if (fore->flow & FLOW_NOW)
  1931.               fore->flow &= ~FLOW_NOW;
  1932.             else
  1933.               fore->flow = fore->flow ? FLOW_AUTOFLAG|FLOW_AUTO|FLOW_NOW : FLOW_AUTOFLAG;
  1934.             SetFlow(fore->flow & FLOW_NOW);
  1935.             Msg(0, "%cflow%s", (fore->flow & FLOW_NOW) ? '+' : '-',
  1936.             (fore->flow & FLOW_AUTOFLAG) ? "(auto)" : "");
  1937.             break;
  1938.           case KEY_CLEAR:
  1939.             if (fore->state == LIT)
  1940.               WriteString(fore, "\033[H\033[J", 6);
  1941.             break;
  1942.           case KEY_RESET:
  1943.             if (fore->state == LIT)
  1944.               WriteString(fore, "\033c", 2);
  1945.             break;
  1946.           case KEY_MONITOR:
  1947.             if (fore->monitor == MON_OFF)
  1948.               {
  1949.             fore->monitor = MON_ON;
  1950.             Msg(0,
  1951.                 "Window %d is now being monitored for all activity.",
  1952.                 ForeNum);
  1953.               }
  1954.             else
  1955.               {
  1956.             fore->monitor = MON_OFF;
  1957.             Msg(0,
  1958.                 "Window %d is no longer being monitored for activity.",
  1959.                 ForeNum);
  1960.               }
  1961.             break;
  1962.           case KEY_HELP:
  1963.             display_help();
  1964.             break;
  1965.           case KEY_LICENSE:
  1966.             display_copyright();
  1967.             break;
  1968. #ifdef COPY_PASTE
  1969.           case KEY_COPY:
  1970.             (void) MarkRoutine(PLAIN);
  1971.             break;
  1972.           case KEY_HISTNEXT:
  1973.             if (MarkRoutine(CRAZY))
  1974.               if (copybuffer != NULL)
  1975.                 {
  1976.                 pastelen = copylen;
  1977.                 pastebuffer = copybuffer;
  1978.               debug("histnext\n");
  1979.                 }
  1980.             break;
  1981.           case KEY_HISTORY:
  1982.             if (MarkRoutine(TRICKY))
  1983.               if (copybuffer != NULL)
  1984.             {
  1985.               pastelen = copylen;
  1986.               pastebuffer = copybuffer;
  1987.               debug1("history new copylen: %d\n", pastelen);
  1988.             }
  1989.             break;
  1990.           case KEY_PASTE:
  1991.             if (copybuffer == NULL)
  1992.               {
  1993. #ifdef NETHACK
  1994.                   if (nethackflag)
  1995.               Msg(0, "Nothing happens.");
  1996.                   else
  1997. #endif
  1998.             Msg(0, "empty buffer");
  1999.             copylen = 0;
  2000.             break;
  2001.               }
  2002.             pastelen = copylen;
  2003.             pastebuffer = copybuffer;
  2004.             break;
  2005.           case KEY_WRITE_BUFFER:
  2006.             if (copybuffer == NULL)
  2007.               {
  2008. #ifdef NETHACK
  2009.                   if (nethackflag)
  2010.               Msg(0, "Nothing happens.");
  2011.                   else
  2012. #endif
  2013.             Msg(0, "empty buffer");
  2014.             copylen = 0;
  2015.             break;
  2016.               }
  2017.             WriteFile(DUMP_EXCHANGE);
  2018.             break;
  2019.           case KEY_READ_BUFFER:
  2020.             ReadFile();
  2021.             break;
  2022.           case KEY_REMOVE_BUFFERS:
  2023.             KillBuffers();
  2024.             break;
  2025. #endif                /* COPY_PASTE */
  2026.           case KEY_VBELL:
  2027.             if (visual_bell)
  2028.               {
  2029.             visual_bell = 0;
  2030.             Msg(0, "switched to audible bell");
  2031.               }
  2032.             else
  2033.               {
  2034.             visual_bell = 1;
  2035.             Msg(0, "switched to visual bell");
  2036.               }
  2037.             break;
  2038.            default:
  2039.             break;
  2040.           }
  2041.         }
  2042.       else
  2043.         ESCseen = 1;
  2044.       --*pilen;
  2045.       s++;
  2046.       break;
  2047.     }
  2048.       else if (*polen < obuf_size)
  2049.     {
  2050.       *p++ = *s;
  2051.       ++*polen;
  2052.     }
  2053.     }
  2054.   return (s);
  2055. }
  2056.  
  2057. /* Send a terminal report as if it were typed. */ 
  2058. void
  2059. Report(wp, fmt, n1, n2)
  2060. struct win *wp;
  2061. char *fmt;
  2062. int n1, n2;
  2063. {
  2064.   register int n, len;
  2065.   char rbuf[40];
  2066.  
  2067.   sprintf(rbuf, fmt, n1, n2);
  2068.   len = strlen(rbuf);
  2069.  
  2070.   for (n = 0; n < MAXWIN; n++)
  2071.     {
  2072.       if (wp == wtab[n])
  2073.     {
  2074.       if ((unsigned)(inlen[n] + len) <= sizeof *inbuf)
  2075.         {
  2076.           bcopy(rbuf, inbuf[n] + inlen[n], len);
  2077.           if (inlen[n] == 0)
  2078.         inbuf_ct++;
  2079.           inlen[n] += len;
  2080.         }
  2081.       break;
  2082.     }
  2083.     }/* for */
  2084. }
  2085.  
  2086. void
  2087. SwitchWindow(n)
  2088. int n;
  2089. {
  2090.   debug1("SwitchWindow %d\n", n);
  2091.   if (!wtab[n])
  2092.     {
  2093.       ShowWindows();
  2094.       return;
  2095.     }
  2096.   if (wtab[n] == fore)
  2097.     {
  2098.       Msg(0, "This IS window %d.", n);
  2099.       return;
  2100.     }
  2101.   SetForeWindow(n);
  2102.   if (!Detached && !in_ovl)
  2103.     Activate(fore->norefresh);
  2104. }
  2105.  
  2106. static void SetForeWindow(n)
  2107. int n;
  2108. {
  2109.   /*
  2110.    * If we come from another window, make it inactive.
  2111.    */
  2112.   if (fore)
  2113.     fore->active = 0;
  2114.   ForeNum = n;
  2115.   fore = wtab[n];
  2116.   if (!Detached && !in_ovl)
  2117.     fore->active = 1;
  2118.   /*
  2119.    * Place the window at the head of the most-recently-used list.
  2120.    */
  2121.   if ((n = WinList) != ForeNum)
  2122.     {
  2123.       /*
  2124.        * we had a bug here. we sometimes ran into n = -1; and crashed.
  2125.        * (this is not the perfect fix. "if (...) break;" inserted. jw.)
  2126.        */
  2127.       while (wtab[n]->WinLink != ForeNum)
  2128.     {
  2129.       if (wtab[n]->WinLink == -1)
  2130.         break;
  2131.       n = wtab[n]->WinLink;
  2132.     }
  2133.       wtab[n]->WinLink = fore->WinLink;
  2134.       fore->WinLink = WinList;
  2135.       WinList = ForeNum;
  2136.     }
  2137. }
  2138.  
  2139. static int NextWindow()
  2140. {
  2141.   register struct win **pp;
  2142.  
  2143.   for (pp = wtab + ForeNum + 1; pp != wtab + ForeNum; ++pp)
  2144.     {
  2145.       if (pp == wtab + MAXWIN)
  2146.     pp = wtab;
  2147.       if (*pp)
  2148.     break;
  2149.     }
  2150.   return pp - wtab;
  2151. }
  2152.  
  2153. static int PreviousWindow()
  2154. {
  2155.   register struct win **pp;
  2156.  
  2157.   for (pp = wtab + ForeNum - 1; pp != wtab + ForeNum; --pp)
  2158.     {
  2159.       if (pp < wtab)
  2160.     pp = wtab + MAXWIN - 1;
  2161.       if (*pp)
  2162.     break;
  2163.     }
  2164.   return pp - wtab;
  2165. }
  2166.  
  2167. static int MoreWindows()
  2168. {
  2169.   if (fore->WinLink != -1)
  2170.     return 1;
  2171. #ifdef NETHACK
  2172.   if (nethackflag)
  2173.     Msg(0, "You cannot escape from window %d!", ForeNum);
  2174.   else
  2175. #endif
  2176.   Msg(0, "No other window.");
  2177.   return 0;
  2178. }
  2179.  
  2180. static void FreeWindow(wp)
  2181. struct win *wp;
  2182. {
  2183. #ifdef UTMPOK
  2184.   RemoveUtmp(wp);
  2185. #endif
  2186. #ifdef SUIDROOT
  2187.   (void) chmod(wp->tty, 0666);
  2188.   (void) chown(wp->tty, 0, 0);
  2189. #endif
  2190.   close(wp->ptyfd);
  2191.   if (wp->logfp != NULL)
  2192.     fclose(wp->logfp);
  2193.   ChangeWindowSize(wp, 0, 0);
  2194.   Free(wp);
  2195. }
  2196.  
  2197. int
  2198. MakeWindow(prog, args, aflag, flowflag, StartAt, dir, lflag, histheight, term)
  2199. char *prog, **args, *dir;
  2200. int aflag, flowflag, StartAt, lflag, histheight;
  2201. char *term; /* if term is nonzero we assume it "vt100" or the like.. */
  2202. {
  2203.   register struct win **pp, *p;
  2204.   register int n, f;
  2205.   int tf, tlflag;
  2206.   char ebuf[10];
  2207. #ifndef TIOCSWINSZ
  2208.   char libuf[20], cobuf[20];
  2209. #endif
  2210.   char tebuf[25];
  2211.  
  2212.   pp = wtab + StartAt;
  2213.   do
  2214.     {
  2215.       if (*pp == 0)
  2216.     break;
  2217.       if (++pp == wtab + MAXWIN)
  2218.     pp = wtab;
  2219.     } while (pp != wtab + StartAt);
  2220.   if (*pp)
  2221.     {
  2222.       Msg(0, "No more windows.");
  2223.       return -1;
  2224.     }
  2225.  
  2226.    if (((tlflag = lflag) == -1) && ((tlflag = loginflag) == -1))
  2227.     tlflag = LOGINDEFAULT;
  2228.  
  2229. #ifdef USRLIMIT
  2230.   /*
  2231.    * Count current number of users, if logging windows in.
  2232.    */
  2233.   if (tlflag == 1 && CountUsers() >= USRLIMIT)
  2234.     {
  2235.       Msg(0, "User limit reached.  Window will not be logged in.");
  2236.       tlflag = 0;
  2237.     }
  2238. #endif
  2239.   n = pp - wtab;
  2240.   debug1("Makewin creating %d\n", n);
  2241.   if ((f = OpenPTY()) == -1)
  2242.     {
  2243.       Msg(0, "No more PTYs.");
  2244.       return -1;
  2245.     }
  2246. #ifdef SYSV
  2247.   (void) fcntl(f, F_SETFL, O_NDELAY);
  2248. #else
  2249.   (void) fcntl(f, F_SETFL, FNDELAY);
  2250. #endif
  2251. #ifdef TIOCPKT
  2252.     {
  2253. # ifdef sgi
  2254.       /*
  2255.        * on IRIX 3.3, regardless of stream head's read mode (RNORM/RMSGN/RMSGD)
  2256.        * we loose data in TIOCPKT mode if our buffer is too small (IOSIZE)
  2257.        * to hold the whole packet at first read().
  2258.        * (Marc Boucher)
  2259.        */
  2260.       int flag = 0;
  2261. # else /* sgi */
  2262.       int flag = 1;
  2263. # endif /* sgi */
  2264.  
  2265.       if (ioctl(f, TIOCPKT, &flag))
  2266.     {
  2267.       Msg(errno, "TIOCPKT ioctl");
  2268.       close(f);
  2269.       return -1;
  2270.     }
  2271.     }
  2272. #endif
  2273.   if ((p = (struct win *) malloc(sizeof(struct win))) == 0)
  2274.     {
  2275.       close(f);
  2276.       Msg_nomem;
  2277.       return -1;
  2278.     }
  2279.   bzero((char *) p, (int) sizeof(struct win));
  2280.   p->ptyfd = f;
  2281.   p->aflag = aflag;
  2282.   if (flowflag < 0)
  2283.     flowflag = default_flow;
  2284.   p->flow = flowflag | ((flowflag & FLOW_AUTOFLAG) ? (FLOW_AUTO|FLOW_NOW) : FLOW_AUTO);
  2285.   if (!prog)
  2286.     prog = Filename(args[0]);
  2287.   strncpy(p->cmd, prog, MAXSTR - 1);
  2288.   if ((prog = rindex(p->cmd, '|')) != NULL)
  2289.     {
  2290.       *prog++ = '\0';
  2291.       prog += strlen(prog);
  2292.       p->akapos = prog - p->cmd;
  2293.       p->autoaka = 0;
  2294.     }
  2295.   else
  2296.     p->akapos = 0;
  2297.   p->monitor = default_monitor;
  2298.   p->norefresh = 0;
  2299.   strncpy(p->tty, TtyName, MAXSTR - 1);
  2300. #ifdef SUIDROOT
  2301.   (void) chown(TtyName, real_uid, real_gid);
  2302. # ifdef UTMPOK
  2303.   (void) chmod(TtyName, tlflag ? TtyMode : (TtyMode & ~022));
  2304. # else
  2305.   (void) chmod(TtyName, TtyMode);
  2306. # endif
  2307. #endif
  2308.  
  2309.   if (histheight < 0)
  2310.     histheight = default_histheight;
  2311.   if (ChangeWindowSize(p, default_width, default_height))
  2312.     {
  2313.       FreeWindow(p);
  2314.       return -1;
  2315.     }
  2316.   ChangeScrollback(p, histheight, default_width);
  2317.   ResetScreen(p);
  2318.   debug("forking...\n");
  2319.   switch (p->wpid = fork())
  2320.     {
  2321.     case -1:
  2322.       Msg(errno, "fork");
  2323.       FreeWindow(p);
  2324.       return -1;
  2325.     case 0:
  2326.       signal(SIGHUP, SIG_DFL);
  2327.       signal(SIGINT, SIG_DFL);
  2328.       signal(SIGQUIT, SIG_DFL);
  2329.       signal(SIGTERM, SIG_DFL);
  2330. #ifdef BSDJOBS
  2331.       signal(SIGTTIN, SIG_DFL);
  2332.       signal(SIGTTOU, SIG_DFL);
  2333. #endif
  2334.       setuid(real_uid);
  2335.       setgid(real_gid);
  2336.       if (dir && chdir(dir) == -1)
  2337.     {
  2338.       SendErrorMsg("Cannot chdir to %s: %s", dir, sys_errlist[errno]);
  2339.       eexit(1);
  2340.     }
  2341.  
  2342.       freetty();
  2343.       if ((tf = open(TtyName, O_RDWR)) == -1)
  2344.     {
  2345.       SendErrorMsg("Cannot open %s: %s", TtyName, sys_errlist[errno]);
  2346.       eexit(1);
  2347.     }
  2348. #ifdef SVR4
  2349.       if (ioctl(tf, I_PUSH, "ptem"))
  2350.     {
  2351.       SendErrorMsg("Cannot I_PUSH ptem %s %s", TtyName, sys_errlist[errno]);
  2352.       eexit(1);
  2353.     }
  2354.       if (ioctl(tf, I_PUSH, "ldterm"))
  2355.     {
  2356.       SendErrorMsg("Cannot I_PUSH ldterm %s %s", TtyName, sys_errlist[errno]);
  2357.       eexit(1);
  2358.     }
  2359.       if (ioctl(tf, I_PUSH, "ttcompat"))
  2360.     {
  2361.       SendErrorMsg("Cannot I_PUSH ttcompat %s %s", TtyName, sys_errlist[errno]);
  2362.       eexit(1);
  2363.     }
  2364. #endif
  2365.       (void) dup2(tf, 0);
  2366.       (void) dup2(tf, 1);
  2367.       (void) dup2(tf, 2);
  2368. #ifdef DEBUG
  2369.       dfp = stderr;
  2370. #endif
  2371.       closeallfiles();
  2372.       fgtty();
  2373. #ifdef TIOCSWINSZ
  2374.       glwz.ws_col = p->width;
  2375.       glwz.ws_row = p->height;
  2376.       (void) ioctl(0, TIOCSWINSZ, &glwz);
  2377. #else
  2378.       sprintf(libuf, "LINES=%d", p->height);
  2379.       sprintf(cobuf, "COLUMNS=%d", p->width);
  2380.       NewEnv[4] = libuf;
  2381.       NewEnv[5] = cobuf;
  2382. #endif
  2383.       SetTTY(0, &OldMode);
  2384.       if (aflag)
  2385.         NewEnv[2] = MakeTermcap(1);
  2386.       else
  2387.         NewEnv[2] = Termcap;
  2388.       if (term && *term && strcmp(screenterm, term) &&
  2389.       (strlen(term) < 20))
  2390.     {
  2391.           char *s1, *s2, tl;
  2392.  
  2393.       sprintf(tebuf, "TERM=%s", term);
  2394.       debug2("Makewindow %d with %s\n", n, tebuf);
  2395.           tl = strlen(term);
  2396.       NewEnv[1] = tebuf;
  2397.           if (s1 = index(Termcap, '|'))
  2398.         {
  2399.           if (s2 = index(++s1, '|'))
  2400.         {
  2401.           if (strlen(Termcap) - (s2 - s1) + tl < 1024)
  2402.             {
  2403.               bcopy(s2, s1 + tl, strlen(s2) + 1);
  2404.               bcopy(term, s1, tl);
  2405.             }
  2406.         }
  2407.             }
  2408.     }
  2409.       sprintf(ebuf, "WINDOW=%d", n);
  2410.       NewEnv[3] = ebuf;
  2411.  
  2412.       execvpe(*args, args, NewEnv);
  2413.       SendErrorMsg("Cannot exec %s: %s", *args, sys_errlist[errno]);
  2414.       exit(1);
  2415.     } /* end fork switch */
  2416.   /*
  2417.    * Place the newly created window at the head of the most-recently-used list.
  2418.    */
  2419.   *pp = p;
  2420.   p->WinLink = WinList;
  2421.   WinList = n;
  2422.   HasWindow = 1;
  2423. #ifdef UTMPOK
  2424.   debug1("MakeWindow will %slog in.\n", tlflag?"":"not ");
  2425.   if (tlflag == 1)
  2426.     SetUtmp(p, n);
  2427.   else
  2428.     p->slot = (slot_t) -1;
  2429. #endif
  2430.   SetForeWindow(n);
  2431.   Activate(0);
  2432.   return n;
  2433. }
  2434.  
  2435. static void execvpe(prog, args, env)
  2436. char *prog, **args, **env;
  2437. {
  2438.   register char *path, *p;
  2439.   char buf[1024];
  2440.   char *shargs[MAXARGS + 1];
  2441.   register int i, eaccess = 0;
  2442.  
  2443.   if (prog[0] == '/')
  2444.     path = "";
  2445.   else if ((path = getenv("PATH")) == 0)
  2446.     path = DefaultPath;
  2447.   do
  2448.     {
  2449.       p = buf;
  2450.       while (*path && *path != ':')
  2451.     *p++ = *path++;
  2452.       if (p > buf)
  2453.     *p++ = '/';
  2454.       strcpy(p, prog);
  2455.       if (*path)
  2456.     ++path;
  2457.       execve(buf, args, env);
  2458.       switch (errno)
  2459.     {
  2460.     case ENOEXEC:
  2461.       shargs[0] = DefaultShell;
  2462.       shargs[1] = buf;
  2463.       for (i = 1; (shargs[i + 1] = args[i]) != NULL; ++i)
  2464.         ;
  2465.       execve(DefaultShell, shargs, env);
  2466.       return;
  2467.     case EACCES:
  2468.       eaccess = 1;
  2469.       break;
  2470.     case ENOMEM:
  2471.     case E2BIG:
  2472.     case ETXTBSY:
  2473.       return;
  2474.     }
  2475.     } while (*path);
  2476.   if (eaccess)
  2477.     errno = EACCES;
  2478. }
  2479.  
  2480.  
  2481. static void LogToggle()
  2482. {
  2483.   char buf[1024];
  2484.  
  2485.   sprintf(buf, "screenlog.%d", ForeNum);
  2486.   if (fore->logfp != NULL)
  2487.     {
  2488.       Msg(0, "Logfile \"%s\" closed.", buf);
  2489.       fclose(fore->logfp);
  2490.       fore->logfp = NULL;
  2491.       return;
  2492.     }
  2493.   if ((fore->logfp = secfopen(buf, "a")) == NULL)
  2494.     {
  2495.       Msg(errno, "Error opening logfile \"%s\"", buf);
  2496.       return;
  2497.     }
  2498.   Msg(0, "%s logfile \"%s\"", ftell(fore->logfp) ? "Appending to" : "Creating", buf);
  2499. }
  2500.  
  2501. #ifdef NOREUID
  2502. static int UserPID;
  2503. static sig_t (*Usersigcld)__P(SIGPROTOARG);
  2504. #endif
  2505. static int UserSTAT;
  2506.  
  2507. int UserContext()
  2508. {
  2509. #ifdef NOREUID
  2510.   if (eff_uid == real_uid)
  2511.     return(1);
  2512. # ifdef SYSV
  2513.   Usersigcld = signal(SIGCLD, SIG_DFL);
  2514. # else
  2515.   Usersigcld = signal(SIGCHLD, SIG_DFL);
  2516. # endif
  2517.   debug("UserContext: forking.\n");
  2518.   switch (UserPID = fork())
  2519.     {
  2520.     case -1:
  2521.       Msg(errno, "fork");
  2522.       return -1;
  2523.     case 0:
  2524.       signal(SIGHUP, SIG_DFL);
  2525.       signal(SIGINT, SIG_IGN);
  2526.       signal(SIGQUIT, SIG_DFL);
  2527.       signal(SIGTERM, SIG_DFL);
  2528. # ifdef BSDJOBS
  2529.       signal(SIGTTIN, SIG_DFL);
  2530.       signal(SIGTTOU, SIG_DFL);
  2531. # endif
  2532.       setuid(real_uid);
  2533.       setgid(real_gid);
  2534.       return 1;
  2535.     default:
  2536.       return 0;
  2537.     }
  2538. #else
  2539.   setreuid(eff_uid, real_uid);
  2540.   setregid(eff_gid, real_gid);
  2541.   return 1;
  2542. #endif
  2543. }
  2544.  
  2545. void
  2546. UserReturn(val)
  2547. int val;
  2548. {
  2549. #if defined(NOREUID)
  2550.   if (eff_uid == real_uid)
  2551.     UserSTAT = val;
  2552.   else
  2553.     exit(val);
  2554. #else
  2555.   setreuid(real_uid, eff_uid);
  2556.   setregid(real_gid, eff_gid);
  2557.   UserSTAT = val;
  2558. #endif
  2559. }
  2560.  
  2561. int UserStatus()
  2562. {
  2563. #ifdef NOREUID
  2564.   int i;
  2565. # ifdef BSDWAIT
  2566.   union wait wstat;
  2567. # else
  2568.   int wstat;
  2569. # endif
  2570.  
  2571.   if (eff_uid == real_uid)
  2572.     return UserSTAT;
  2573.   if (UserPID < 0)
  2574.     return -1;
  2575.   while ((errno = 0, i = wait(&wstat)) != UserPID)
  2576.     if (i < 0 && errno != EINTR)
  2577.       break;
  2578. # ifdef SYSV
  2579.   (void) signal(SIGCLD, Usersigcld);
  2580. # else
  2581.   (void) signal(SIGCHLD, Usersigcld);
  2582. # endif
  2583.   if (i == -1)
  2584.     return -1;
  2585.   return (WEXITSTATUS(wstat));
  2586. #else
  2587.   return UserSTAT;
  2588. #endif
  2589. }
  2590.  
  2591. static void ShowWindows()
  2592. {
  2593.   char buf[1024];
  2594.   register char *s;
  2595.   register struct win **pp, *p;
  2596.   register int i, OtherNum = fore->WinLink;
  2597.   register char *cmd;
  2598.  
  2599.   for (i = 0, s = buf, pp = wtab; pp < wtab + MAXWIN; ++i, ++pp)
  2600.     {
  2601.       if ((p = *pp) == 0)
  2602.     continue;
  2603.  
  2604.       if (p->akapos)
  2605.     {
  2606.       if (*(p->cmd + p->akapos) && *(p->cmd + p->akapos - 1) != ':')
  2607.         cmd = p->cmd + p->akapos;
  2608.       else
  2609.         cmd = p->cmd + strlen(p->cmd) + 1;
  2610.     }
  2611.       else
  2612.     cmd = p->cmd;
  2613.       if (s - buf + 5 + strlen(cmd) > fore->width - 1)
  2614.     break;
  2615.       if (s > buf)
  2616.     {
  2617.       *s++ = ' ';
  2618.       *s++ = ' ';
  2619.     }
  2620.       *s++ = i + '0';
  2621.       if (i == ForeNum)
  2622.     *s++ = '*';
  2623.       else if (i == OtherNum)
  2624.     *s++ = '-';
  2625.       if (p->monitor == MON_DONE)
  2626.     *s++ = '@';
  2627.       if (p->bell == BELL_DONE)
  2628.     *s++ = '!';
  2629. #ifdef UTMPOK
  2630.       if (p->slot != (slot_t) 0 && p->slot != (slot_t) -1)
  2631.     *s++ = '$';
  2632. #endif
  2633.       if (p->logfp != NULL)
  2634.     {
  2635.       strcpy(s, "(L)");
  2636.       s += 3;
  2637.     }
  2638.       *s++ = ' ';
  2639.       strcpy(s, cmd);
  2640.       s += strlen(s);
  2641.       if (i == ForeNum)
  2642.     {
  2643.       /* 
  2644.        * this is usually done by Activate(), but when looking
  2645.        * on your current window, you may get annoyed, as there is still
  2646.        * that temporal '!' and '@' displayed.
  2647.        * So we remove that after displaying it once.
  2648.        */
  2649.       p->bell = BELL_OFF;
  2650.       if (p->monitor != MON_OFF)
  2651.         p->monitor = MON_ON;
  2652.     }
  2653.     }
  2654.   *s++ = ' ';
  2655.   *s = '\0';
  2656.   Msg(0, "%s", buf);
  2657. }
  2658.  
  2659. static void ShowTime()
  2660. {
  2661.   char buf[512];
  2662.   struct tm *tp;
  2663.   time_t now;
  2664.  
  2665.   (void) time(&now);
  2666.   tp = localtime(&now);
  2667.   sprintf(buf, "%2d:%02.2d:%02.2d %s", tp->tm_hour, tp->tm_min, tp->tm_sec,
  2668.       HostName);
  2669.   {
  2670.     static int loads = 0;
  2671.     double loadav[3];
  2672.     int n;
  2673.  
  2674.     if (loads >= 0)        /* If it failed, don't try again.  */
  2675.       {
  2676.     loads = getloadavg(loadav, 3);
  2677.     for (n = 0; n < loads; n++)
  2678.       {
  2679.         char *p = buf + strlen(buf);
  2680.         sprintf(p, " %2.2f", loadav[n]);
  2681.       }
  2682.       }
  2683.   }
  2684.   Msg(0, "%s", buf);
  2685. }
  2686.  
  2687. static void ShowInfo()
  2688. {
  2689.   char buf[512], *p;
  2690.   register struct win *wp = fore;
  2691.   register int i;
  2692.  
  2693.   sprintf(buf, "(%d,%d)/(%d,%d)+%d %c%sflow %cins %corg %cwrap %capp %clog %cmon %cr",
  2694.       wp->x + 1, wp->y + 1, wp->width, wp->height,
  2695.       wp->histheight,
  2696.       (wp->flow & FLOW_NOW) ? '+' : '-',
  2697.       (wp->flow & FLOW_AUTOFLAG) ? "" : ((wp->flow & FLOW_AUTO) ? "(+)" : "(-)"),
  2698.       wp->insert ? '+' : '-', wp->origin ? '+' : '-',
  2699.       wp->wrap ? '+' : '-', wp->keypad ? '+' : '-',
  2700.       (wp->logfp != NULL) ? '+' : '-',
  2701.       (wp->monitor != MON_OFF) ? '+' : '-',
  2702.       wp->norefresh ? '-' : '+');
  2703.   if (ISO2022)
  2704.     {
  2705.       p = buf + strlen(buf);
  2706.       sprintf(p, " G%1d [", wp->LocalCharset);
  2707.       for (i = 0; i < 4; i++)
  2708.     p[i + 5] = wp->charsets[i] ? wp->charsets[i] : 'B';
  2709.       p[9] = ']';
  2710.       p[10] = '\0';
  2711.     }
  2712.   Msg(0, "%s", buf);
  2713. }
  2714.  
  2715. #if defined(sequent) || defined(_SEQUENT_) || defined(SVR4)
  2716.  
  2717. static int OpenPTY()
  2718. {
  2719.   char *m, *s;
  2720.   register int f;
  2721. # ifdef SVR4
  2722.   char *ptsname();
  2723.   sig_t (*sigcld)();
  2724.  
  2725.   if ((f = open("/dev/ptmx", O_RDWR)) == -1)
  2726.     return(-1);
  2727.  
  2728.   /*
  2729.    * SIGCLD set to SIG_DFL for grantpt() because it fork()s and
  2730.    * exec()s pt_chmod
  2731.    */
  2732.   sigcld = signal(SIGCLD, SIG_DFL);
  2733.        
  2734.   if ((m = ptsname(f)) == NULL || unlockpt(f) || grantpt(f))
  2735.     {
  2736.       signal(SIGCLD, sigcld);
  2737.       close(f);
  2738.       return(-1);
  2739.     } 
  2740.   signal(SIGCLD, sigcld);
  2741.   strncpy(TtyName, m, sizeof TtyName);
  2742. # else /* SVR4 */
  2743.   if ((f = getpseudotty(&s, &m)) < 0)
  2744.     return(-1);
  2745.   strncpy(PtyName, m, sizeof PtyName);
  2746.   strncpy(TtyName, s, sizeof TtyName);
  2747. # endif /* SVR4 */
  2748. # ifdef POSIX
  2749.   tcflush(f, TCIOFLUSH);
  2750. # else
  2751.   (void) ioctl(f, TIOCFLUSH, (char *) 0);
  2752. # endif
  2753. # ifdef LOCKPTY
  2754.   (void) ioctl(f, TIOCEXCL, (char *) 0);
  2755. # endif
  2756.   return (f);
  2757. }
  2758.  
  2759. #else /* defined(sequent) || defined(_SEQUENT_) || defined(SVR4) */
  2760. # ifdef MIPS
  2761.  
  2762. static int OpenPTY()
  2763. {
  2764.   register char *p, *l, *d;
  2765.   register f, tf;
  2766.   register my_minor;
  2767.   struct stat buf;
  2768.    
  2769.   strcpy(PtyName, PtyProto);
  2770.   for (p = PtyName; *p != 'X'; ++p)
  2771.     ;
  2772.   for (l = PTY_FIRST_CHARS; *p = *l; ++l)
  2773.     {
  2774.       for (d = PTY_SECOND_CHARS; p[1] = *d; ++d)
  2775.     {
  2776.       if ((f = open(PtyName, O_RDWR)) != -1)
  2777.         {
  2778.           fstat(f, &buf);
  2779.           my_minor = minor(buf.st_rdev);
  2780.           sprintf(TtyName, "/dev/ttyq%d", my_minor);
  2781.           if ((tf = open(TtyName, O_RDWR)) != -1)
  2782.         {
  2783.           close(tf);
  2784. #ifdef LOCKPTY
  2785.           (void) ioctl(f, TIOCEXCL, (char *)0);
  2786. #endif
  2787.           return f;
  2788.         }
  2789.           close(f);
  2790.         }
  2791.     }
  2792.     }
  2793.   return -1;
  2794. }
  2795.  
  2796. # else  /* MIPS */
  2797. #  ifdef sgi
  2798.  
  2799. static int OpenPTY()
  2800. {
  2801.   register f;
  2802.   register my_minor;
  2803.   struct stat buf;
  2804.    
  2805.   strcpy(PtyName, "/dev/ptc");
  2806.   f = open(PtyName, O_RDWR|O_NDELAY);
  2807.   if (f >= 0)
  2808.     {
  2809.       if (fstat(f, &buf) < 0)
  2810.     {
  2811.       close(f);
  2812.       return -1;
  2813.     }
  2814.       my_minor = minor(buf.st_rdev);
  2815.       sprintf(TtyName, "/dev/ttyq%d", my_minor);
  2816.     }
  2817.   return f;
  2818. }
  2819.  
  2820. #  else /* sgi */
  2821. #   ifdef _AIX /* RS6000 */
  2822.  
  2823. static int OpenPTY()
  2824. {
  2825.   register int i, f, tf;
  2826.  
  2827.   strcpy (PtyName, "/dev/ptc");
  2828.   if ((f = open (PtyName, O_RDWR)) != -1)
  2829.     {
  2830.       strcpy (TtyName, ttyname (f));
  2831.       strcpy (PtyName, TtyName);
  2832.       PtyName [7] = 'c';
  2833. #ifdef LOCKPTY
  2834.       if (ioctl (f, TIOCEXCL, (char *) 0) == -1)
  2835.     return -1;
  2836. #endif
  2837.       if ((tf = open (TtyName, O_RDWR)) != -1)
  2838.     {
  2839.       close (tf);
  2840.       return f;
  2841.     }
  2842.       close (f);
  2843.     }
  2844.   return -1;
  2845. }
  2846.  
  2847. #   else /* _AIX, RS6000 */
  2848.  
  2849. static int OpenPTY()
  2850. {
  2851.   register char *p, *q, *l, *d;
  2852.   register int f, tf;
  2853.  
  2854. #    if !defined(hpux)
  2855.   debug("Hello, You are none of: sequent, _SEQUENT_, SVR4, MIPS, sgi, AIX\n");
  2856.   debug("       This OpenPTY() is for hpux, ... and for you?\n");
  2857. #    endif
  2858.   strcpy(PtyName, PtyProto);
  2859.   strcpy(TtyName, TtyProto);
  2860.   for (p = PtyName; *p != 'X'; ++p)
  2861.     ;
  2862.   for (q = TtyName; *q != 'X'; ++q)
  2863.     ;
  2864.   for (l = PTY_FIRST_CHARS; (*p = *l) != '\0'; ++l)
  2865.     {
  2866.       for (d = PTY_SECOND_CHARS; (p[1] = *d) != '\0'; ++d)
  2867.     {
  2868.       if ((f = open(PtyName, O_RDWR)) != -1)
  2869.         {
  2870.           q[0] = *l;
  2871.           q[1] = *d;
  2872.           if ((tf = open(TtyName, O_RDWR)) != -1)
  2873.         {
  2874.           /* close tf, thus we also get rid of an unwanted
  2875.            * controlling terminal! 
  2876.            */
  2877.           close(tf);
  2878. #ifdef LOCKPTY
  2879.           (void) ioctl(f, TIOCEXCL, (char *) 0);
  2880. #endif
  2881.           return f;
  2882.         }
  2883.           close(f);
  2884.         }
  2885.     }
  2886.     }
  2887.   return -1;
  2888. }
  2889.  
  2890. #   endif /* _AIX, RS6000 */
  2891. #  endif /* sgi */
  2892. # endif /* MIPS */
  2893. #endif
  2894.  
  2895. void 
  2896. SetTTY(fd, mp)
  2897. int fd;
  2898. struct mode *mp;
  2899. {
  2900.   errno = 0;
  2901. #ifdef POSIX
  2902.   tcsetattr(fd, TCSADRAIN, &mp->tio);
  2903. # ifdef hpux
  2904.   ioctl(fd, TIOCSLTC, &mp->m_ltchars);
  2905. # endif
  2906. #else
  2907. # ifdef TERMIO
  2908.   ioctl(fd, TCSETA, &mp->tio);
  2909. # else
  2910.   /* ioctl(fd, TIOCSETP, &mp->m_ttyb); */
  2911.   ioctl(fd, TIOCSETC, &mp->m_tchars);
  2912.   ioctl(fd, TIOCSLTC, &mp->m_ltchars);
  2913.   ioctl(fd, TIOCLSET, &mp->m_lmode);
  2914.   ioctl(fd, TIOCSETD, &mp->m_ldisc);
  2915.   ioctl(fd, TIOCSETP, &mp->m_ttyb);
  2916. # endif
  2917. #endif
  2918.   if (errno)
  2919.     Msg(0, "SetTTY: ioctl failed");
  2920. }
  2921.  
  2922. void
  2923. GetTTY(fd, mp)
  2924. int fd;
  2925. struct mode *mp;
  2926. {
  2927.   errno = 0;
  2928. #ifdef POSIX
  2929.   tcgetattr(fd, &mp->tio);
  2930. # ifdef hpux
  2931.   ioctl(fd, TIOCGLTC, &mp->m_ltchars);
  2932. # endif
  2933. #else
  2934. # ifdef TERMIO
  2935.   ioctl(fd, TCGETA, &mp->tio);
  2936. # else
  2937.   ioctl(fd, TIOCGETP, &mp->m_ttyb);
  2938.   ioctl(fd, TIOCGETC, &mp->m_tchars);
  2939.   ioctl(fd, TIOCGLTC, &mp->m_ltchars);
  2940.   ioctl(fd, TIOCLGET, &mp->m_lmode);
  2941.   ioctl(fd, TIOCGETD, &mp->m_ldisc);
  2942. # endif
  2943. #endif
  2944.   if (errno)
  2945.     Msg(0, "GetTTY: ioctl failed");
  2946. }
  2947.  
  2948. void
  2949. SetMode(op, np)
  2950. struct mode *op, *np;
  2951. {
  2952.   *np = *op;
  2953.  
  2954. #if defined(TERMIO) || defined(POSIX)
  2955.   np->tio.c_iflag &= ~ICRNL;
  2956. # ifdef ONLCR
  2957.   np->tio.c_oflag &= ~ONLCR;
  2958. # endif
  2959.   np->tio.c_lflag &= ~(ICANON | ECHO);
  2960.  
  2961.   /*
  2962.    * Unfortunately, the master process never will get SIGINT if the real
  2963.    * terminal is different from the one on which it was originaly started
  2964.    * (process group membership has not been restored or the new tty could not
  2965.    * be made controlling again). In my solution, it is the attacher who
  2966.    * receives SIGINT (because it is always correctly associated with the real
  2967.    * tty) and forwards it to the master [kill(MasterPid, SIGINT)]. 
  2968.    * Marc Boucher (marc@CAM.ORG)
  2969.    */
  2970.   np->tio.c_lflag |= ISIG;
  2971.   /* 
  2972.    * careful, careful catche monkey..
  2973.    * never set VMIN and VTIME to zero, if you want blocking io.
  2974.    */
  2975.   np->tio.c_cc[VMIN] = 1;
  2976.   np->tio.c_cc[VTIME] = 0;
  2977. #ifdef VSTART
  2978.   startc = op->tio.c_cc[VSTART];
  2979. #endif
  2980. #ifdef VSTOP
  2981.   stopc = op->tio.c_cc[VSTOP];
  2982. #endif
  2983.   if (iflag)
  2984.     intrc = op->tio.c_cc[VINTR];
  2985.   else
  2986.     intrc = np->tio.c_cc[VINTR] = 0377;
  2987.   np->tio.c_cc[VQUIT] = 0377;
  2988.   if (flow == 0)
  2989.     {
  2990.       np->tio.c_cc[VINTR] = 0377;
  2991. #ifdef VSTART
  2992.       np->tio.c_cc[VSTART] = 0377;
  2993. #endif
  2994. #ifdef VSTOP
  2995.       np->tio.c_cc[VSTOP] = 0377;
  2996. #endif
  2997.       np->tio.c_iflag &= ~IXON;
  2998.     }
  2999. #ifdef VDISCARD
  3000.   np->tio.c_cc[VDISCARD] = 0377;
  3001. #endif
  3002. #ifdef VSUSP
  3003.   np->tio.c_cc[VSUSP] = 0377;
  3004. #endif
  3005. # ifdef hpux
  3006.   np->m_ltchars.t_suspc = 0377;
  3007.   np->m_ltchars.t_dsuspc = 0377;
  3008.   np->m_ltchars.t_flushc = 0377;
  3009.   np->m_ltchars.t_lnextc = 0377;
  3010. # else
  3011. #  ifdef VDSUSP
  3012.   np->tio.c_cc[VDSUSP] = 0377;
  3013. #  endif
  3014. # endif
  3015. #else
  3016.   startc = op->m_tchars.t_startc;
  3017.   stopc = op->m_tchars.t_stopc;
  3018.   if (iflag)
  3019.     intrc = op->m_tchars.t_intrc;
  3020.   else
  3021.     intrc = np->m_tchars.t_intrc = -1;
  3022.   np->m_ttyb.sg_flags &= ~(CRMOD | ECHO);
  3023.   np->m_ttyb.sg_flags |= CBREAK;
  3024.   np->m_tchars.t_quitc = -1;
  3025.   if (flow == 0)
  3026.     {
  3027.       np->m_tchars.t_intrc = -1;
  3028.       np->m_tchars.t_startc = -1;
  3029.       np->m_tchars.t_stopc = -1;
  3030.     }
  3031.   np->m_ltchars.t_suspc = -1;
  3032.   np->m_ltchars.t_dsuspc = -1;
  3033.   np->m_ltchars.t_flushc = -1;
  3034.   np->m_ltchars.t_lnextc = -1;
  3035. #endif                /* defined(TERMIO) || defined(POSIX) */
  3036. }
  3037.  
  3038. void
  3039. SetFlow(on)
  3040. int on;
  3041. {
  3042.   if (flow == on)
  3043.     return;
  3044. #if defined(TERMIO) || defined(POSIX)
  3045.   if (on)
  3046.     {
  3047.       NewMode.tio.c_cc[VINTR] = intrc;
  3048. #ifdef VSTART
  3049.       NewMode.tio.c_cc[VSTART] = startc;
  3050. #endif
  3051. #ifdef VSTOP
  3052.       NewMode.tio.c_cc[VSTOP] = stopc;
  3053. #endif
  3054.       NewMode.tio.c_iflag |= IXON;
  3055.     }
  3056.   else
  3057.     {
  3058.       NewMode.tio.c_cc[VINTR] = 0377;
  3059. #ifdef VSTART
  3060.       NewMode.tio.c_cc[VSTART] = 0377;
  3061. #endif
  3062. #ifdef VSTOP
  3063.       NewMode.tio.c_cc[VSTOP] = 0377;
  3064. #endif
  3065.       NewMode.tio.c_iflag &= ~IXON;
  3066.     }
  3067. # ifdef POSIX
  3068.   if (tcsetattr(0, TCSADRAIN, &NewMode.tio))
  3069. # else
  3070.   if (ioctl(0, TCSETA, &NewMode.tio) != 0)
  3071. # endif
  3072.     debug1("SetFlow: ioctl errno %d\n", errno);
  3073. #else
  3074.   if (on)
  3075.     {
  3076.       NewMode.m_tchars.t_intrc = intrc;
  3077.       NewMode.m_tchars.t_startc = startc;
  3078.       NewMode.m_tchars.t_stopc = stopc;
  3079.     }
  3080.   else
  3081.     {
  3082.       NewMode.m_tchars.t_intrc = -1;
  3083.       NewMode.m_tchars.t_startc = -1;
  3084.       NewMode.m_tchars.t_stopc = -1;
  3085.     }
  3086.   if (ioctl(0, TIOCSETC, &NewMode.m_tchars) != 0)
  3087.     debug1("SetFlow: ioctl errno %d\n", errno);
  3088. #endif                /* defined(TERMIO) || defined(POSIX) */
  3089.   flow = on;
  3090. }
  3091.  
  3092. /* we return 1 if we could attach one, or 0 if none */
  3093. static int Attach(how)
  3094. int how;
  3095. {
  3096.   int lasts;
  3097.   struct msg m;
  3098.   struct stat st;
  3099.   char *s;
  3100.  
  3101.   if (how == MSG_WINCH)
  3102.     {
  3103.       bzero((char *) &m, sizeof(m));
  3104.       m.type = how;
  3105.       if ((lasts = MakeClientSocket(0, SockName)) >= 0)
  3106.     {
  3107.           write(lasts, &m, sizeof(m));
  3108.           close(lasts);
  3109.     }
  3110.       return 0;
  3111.     }
  3112.  
  3113.   if (how == MSG_CONT)
  3114.     {
  3115.       if ((lasts = MakeClientSocket(0, SockName)) < 0)
  3116.         {
  3117.           printf("Sorry, cannot contact session \"%s\" again\r\n",
  3118.                  SockName);
  3119.           sleep(2);
  3120.           how = MSG_ATTACH;
  3121.         }
  3122.     }
  3123.     
  3124.   if (how != MSG_CONT)
  3125.     {
  3126.       switch (FindSocket(how, &lasts))
  3127.         {
  3128.         case 0:
  3129.           if (rflag == 2)
  3130.         return 0;
  3131.           if (quietflag)
  3132.         eexit(10);
  3133.           if (SockName && *SockName)
  3134.             Msg(0, "There is no screen to be %sed matching %s.", 
  3135.             dflag ? "detach" : "resum", SockName);
  3136.           else
  3137.             Msg(0, "There is no screen to be %sed.",
  3138.                 dflag ? "detach" : "resum");
  3139.           /* NOTREACHED */
  3140.         case 1:
  3141.           break;
  3142.         default:
  3143.           Msg(0, "Type \"screen [-d] -r [pid.]tty.host\" to resume one of them.");
  3144.           /* NOTREACHED */
  3145.         }
  3146.       /*
  3147.        * Go in UserContext. Advantage is, you can kill your attacher
  3148.        * when things go wrong. Any disadvantages? jw.
  3149.        */
  3150.       setuid(real_uid);
  3151.       setgid(real_gid);
  3152.  
  3153.       SockName = SockNamePtr;
  3154.       MasterPid = 0;
  3155.       while (*SockName)
  3156.         {
  3157.           if (*SockName > '9' || *SockName < '0')
  3158.         break;
  3159.           MasterPid = 10 * MasterPid + *SockName - '0';
  3160.           SockName++;
  3161.         }
  3162.       SockName = SockNamePtr;
  3163.       debug1("Attach decided, it is '%s'\n", SockPath);
  3164.       debug1("Attach found MasterPid == %d\n", MasterPid);
  3165.       if (stat(SockPath, &st) == -1)
  3166.         Msg(errno, "stat %s", SockPath);
  3167.       if ((st.st_mode & 0700) != (dflag ? 0700 : 0600))
  3168.         Msg(0, "That screen is %sdetached.", dflag ? "already " : "not ");
  3169. #ifdef REMOTE_DETACH
  3170.       if (dflag &&
  3171.           (how == MSG_ATTACH || how == MSG_DETACH || how == MSG_POW_DETACH))
  3172.         {
  3173.           strcpy(m.m.detach.tty, attach_tty);
  3174.           debug1("attach_tty is %s\n", attach_tty);
  3175.           m.m.detach.dpid = getpid();
  3176. # ifdef POW_DETACH
  3177.           if (dflag == 2)
  3178.         m.type = MSG_POW_DETACH;
  3179.           else
  3180. # endif
  3181.         m.type = MSG_DETACH;
  3182.           if (write(lasts, (char *) &m, sizeof(m)) != sizeof(m))
  3183.             Msg(errno, "write");
  3184.           close(lasts);
  3185.           if (how != MSG_ATTACH)
  3186.             return 0;    /* we detached it. jw. */
  3187.           sleep(1);    /* we dont want to overrun our poor backend. jw. */
  3188.           if ((lasts = MakeClientSocket(0, SockName)) == -1)
  3189.             Msg(0, "Cannot contact screen again. Shit.");
  3190.         }
  3191. #endif
  3192.     }
  3193.   m.type = how;
  3194.   strcpy(m.m.attach.tty, attach_tty);
  3195.   debug1("attach_tty is %s\n", attach_tty);
  3196.   s = getenv("TERM");
  3197.   if (s)
  3198.     {
  3199.       if (strlen(s) >= MAXPATH - 5)
  3200.     Msg(0, "$TERM too long - sorry.");
  3201.       sprintf(m.m.attach.envterm, "TERM=%s", s);
  3202.     }
  3203.   else
  3204.     *m.m.attach.envterm = '\0';
  3205.   debug1("attach: sending %d bytes... ", sizeof m);
  3206.  
  3207.   m.m.attach.apid = getpid();
  3208.   m.m.attach.adaptflag = adaptflag;
  3209.   m.m.attach.lines = m.m.attach.columns = 0;
  3210.   if (s = getenv("LINES"))
  3211.     m.m.attach.lines = atoi(s);
  3212.   if (s = getenv("COLUMNS"))
  3213.     m.m.attach.columns = atoi(s);
  3214.  
  3215. #ifdef PASSWORD
  3216.   if (how == MSG_ATTACH || how == MSG_CONT)
  3217.     trysend(lasts, &m, m.m.attach.password);
  3218.   else
  3219. #endif
  3220.     {
  3221.       if (write(lasts, (char *) &m, sizeof(m)) != sizeof(m))
  3222.     Msg(errno, "write");
  3223.       close(lasts);
  3224.     }
  3225.   debug1("Attach(%d): sent\n", m.type);
  3226.   Suspended = 0;
  3227.   rflag = 0;
  3228.   return 1;
  3229. }
  3230.  
  3231.  
  3232. #ifdef PASSWORD
  3233.  
  3234. static trysendstat;
  3235.  
  3236. static sig_t trysendok(SIGDEFARG)
  3237. {
  3238.   trysendstat = 1;
  3239. }
  3240.  
  3241. static sig_t trysendfail(SIGDEFARG)
  3242. {
  3243.   trysendstat = -1;
  3244. # ifdef SYSV
  3245.   signal(SIG_PW_FAIL, trysendfail);
  3246. # endif /* SYSV */
  3247. }
  3248.  
  3249. static char screenpw[9];
  3250.  
  3251. static void trysend(fd, m, pwto)
  3252. int fd;
  3253. struct msg *m;
  3254. char *pwto;
  3255. {
  3256.   char *npw = NULL;
  3257.   sig_t (*sighup)();
  3258.   sig_t (*sigusr1)();
  3259.   int tries;
  3260.  
  3261.   sigusr1 = signal(SIG_PW_OK, trysendok);
  3262.   sighup = signal(SIG_PW_FAIL, trysendfail);
  3263.   for (tries = 0; ; )
  3264.     {
  3265.       strcpy(pwto, screenpw);
  3266.       trysendstat = 0;
  3267.       if (write(fd, (char *) m, sizeof(*m)) != sizeof(*m))
  3268.     Msg(errno, "write");
  3269.       close(fd);
  3270.       while (trysendstat == 0)
  3271.     pause();
  3272.       if (trysendstat > 0)
  3273.     {
  3274.       signal(SIG_PW_OK, sigusr1);
  3275.       signal(SIG_PW_FAIL, sighup);
  3276.       return;
  3277.     }
  3278.       if (++tries > 1 || (npw = getpass("Screen Password:")) == 0 || *npw == 0)
  3279.     Msg(0, "Password incorrect");
  3280.       strncpy(screenpw, npw, 8);
  3281.       if ((fd = MakeClientSocket(0, SockName)) == -1)
  3282.     Msg(0, "Cannot contact screen again. Shit.");
  3283.     }
  3284. }
  3285. #endif /* PASSWORD */
  3286.  
  3287.  
  3288. /*
  3289.  * Unfortunatelly this is also the SIGHUP handler, so we have to
  3290.  * check, if the backend is already detached.
  3291.  */
  3292.  
  3293. static sig_t AttacherFinit(SIGDEFARG)
  3294. {
  3295.   struct stat statb;
  3296.   struct msg m;
  3297.   int s;
  3298.  
  3299.   debug("AttacherFinit();\n");
  3300.   signal(SIGHUP, SIG_IGN);
  3301.   /* Check if signal comes from backend */
  3302.   if (SockName)
  3303.     {
  3304.       strcpy(SockNamePtr, SockName);
  3305.       if (stat(SockPath, &statb) == 0 && (statb.st_mode & 0777) != 0600)
  3306.     {
  3307.       debug("Detaching backend!\n");
  3308.       bzero((char *) &m, sizeof(m));
  3309.       strcpy(m.m.detach.tty, attach_tty);
  3310.           debug1("attach_tty is %s\n", attach_tty);
  3311.       m.m.detach.dpid = getpid();
  3312.       m.type = MSG_HANGUP;
  3313.       if ((s = MakeClientSocket(0, SockName)) >= 0)
  3314.         {
  3315.           write(s, &m, sizeof(m));
  3316.           close(s);
  3317.         }
  3318.     }
  3319.     }
  3320.   exit(0);
  3321. #ifndef SIGVOID
  3322.   return((sig_t) 0);
  3323. #endif
  3324. }
  3325.  
  3326. #ifdef POW_DETACH
  3327. static sig_t AttacherFinitBye(SIGDEFARG)
  3328. {
  3329.   int ppid;
  3330.   debug("AttacherFintBye()\n");
  3331.   freetty();
  3332.   setuid(real_uid);
  3333.   setgid(real_gid);
  3334.   /* we don't want to disturb init (even if we were root), eh? jw */
  3335.   if ((ppid = getppid()) > 1)
  3336.     Kill(ppid, SIGHUP);        /* carefully say good bye. jw. */
  3337.   exit(0);
  3338. #ifndef SIGVOID
  3339.   return((sig_t) 0);
  3340. #endif
  3341. }
  3342. #endif
  3343.  
  3344. static SuspendPlease;
  3345.  
  3346. static sig_t SigStop(SIGDEFARG)
  3347. {
  3348.   debug("SigStop()\n");
  3349.   SuspendPlease = 1;
  3350. #ifndef SIGVOID
  3351.   return((sig_t) 0);
  3352. #endif
  3353. }
  3354.  
  3355. #ifdef LOCK
  3356. static LockPlease;
  3357.  
  3358. static sig_t DoLock(SIGDEFARG)
  3359. {
  3360.   debug("DoLock()\n");
  3361.   LockPlease = 1;
  3362. # ifdef SYSV
  3363.   signal(SIG_LOCK, DoLock);
  3364. # endif
  3365. # ifndef SIGVOID
  3366.   return((sig_t) 0);
  3367. # endif
  3368. }
  3369. #endif
  3370.  
  3371. #if defined(SIGWINCH) && defined(TIOCGWINSZ)
  3372. static SigWinchPlease;
  3373.  
  3374. static sig_t SigAttWinch(SIGDEFARG)
  3375. {
  3376.   debug("SigAttWinch()\n");
  3377.   SigWinchPlease = 1;
  3378. # ifndef SIGVOID
  3379.   return((sig_t) 0);
  3380. # endif
  3381. }
  3382. #endif
  3383.  
  3384. static void Attacher()
  3385. {
  3386.   /*
  3387.    * permanent in UserContext. Advantage is, you can kill your attacher
  3388.    * when things go wrong. Any disadvantages? jw.
  3389.    */
  3390.   setuid(real_uid);    /* XXX: already done in Attach() */
  3391.   setgid(real_gid);    /* XXX: already done in Attach() */
  3392.  
  3393.   signal(SIGHUP, AttacherFinit);
  3394.   signal(SIG_BYE, AttacherFinit);
  3395. #ifdef POW_DETACH
  3396.   signal(SIG_POWER_BYE, AttacherFinitBye);
  3397. #endif
  3398. #ifdef LOCK
  3399.   signal(SIG_LOCK, DoLock);
  3400. #endif
  3401.   signal(SIGINT, AttacherSigInt);
  3402. #ifdef BSDJOBS
  3403.   signal(SIG_STOP, SigStop);
  3404. #endif
  3405. #if defined(SIGWINCH) && defined(TIOCGWINSZ)
  3406.   signal(SIGWINCH, SigAttWinch);
  3407. #endif
  3408. #ifdef DEBUG
  3409. # ifdef SYSV
  3410.   signal(SIGCLD, FEChld);
  3411. # else
  3412.   signal(SIGCHLD, FEChld);
  3413. # endif
  3414. #endif
  3415.   debug("attacher: going for a nap.\n");
  3416.   dflag = 0;
  3417.   while (1)
  3418.     {
  3419.       pause();
  3420.       debug("attacher: huh! a signal!\n");
  3421. #ifdef DEBUG
  3422.       if (FEpanic)
  3423.         {
  3424.       printf("\n\rSuddenly the Dungeon collapses!! - You die...\n\r");
  3425.       SetTTY(0, &OldMode);
  3426.       eexit(1);
  3427.         }
  3428. #endif
  3429. #ifdef BSDJOBS
  3430.       if (SuspendPlease)
  3431.     {
  3432.       SuspendPlease = 0;
  3433.       signal(SIGTSTP, SIG_DFL);
  3434.       debug("attacher: killing myself SIGTSTP\n");
  3435.       kill(getpid(), SIGTSTP);
  3436.  
  3437.       debug1("attacher: continuing from stop(%d)\n", Suspended);
  3438.       signal(SIG_STOP, SigStop);
  3439.       (void) Attach(MSG_CONT);
  3440.     }
  3441. #endif
  3442. #ifdef LOCK
  3443.       if (LockPlease)
  3444.     {
  3445.       LockPlease = 0;
  3446.       LockTerminal();
  3447. # ifdef SYSV
  3448.       signal(SIG_LOCK, DoLock);
  3449. # endif
  3450.       (void) Attach(MSG_CONT);
  3451.     }
  3452. #endif    /* LOCK */
  3453. #if defined(SIGWINCH) && defined(TIOCGWINSZ)
  3454.       if (SigWinchPlease)
  3455.     {
  3456.       SigWinchPlease = 0;
  3457. # ifdef SYSV
  3458.       signal(SIGWINCH, SigAttWinch);
  3459. # endif
  3460.       (void) Attach(MSG_WINCH);
  3461.     }
  3462. #endif    /* SIGWINCH */
  3463.     }
  3464. }
  3465.  
  3466. #ifdef LOCK
  3467.  
  3468. /* ADDED by Rainer Pruy 10/15/87 */
  3469. /* POLISHED by mls. 03/10/91 */
  3470.  
  3471. static char LockEnd[] = "Welcome back to screen !!\n";
  3472.  
  3473. static void LockTerminal()
  3474. {
  3475.   char *prg;
  3476.   int sig, pid;
  3477.   sig_t (*sigs[NSIG])__P(SIGPROTOARG);
  3478.  
  3479.   for (sig = 1; sig < NSIG; sig++)
  3480.     {
  3481.       sigs[sig] = signal(sig, SIG_IGN);
  3482.     }
  3483.   SetTTY(0, &OldMode);
  3484.   printf("\n");
  3485.  
  3486.   prg = getenv("LOCKPRG");
  3487.   if (prg && strcmp(prg, "builtin") && !access(prg, X_OK))
  3488.     {
  3489. # ifdef SYSV
  3490.       signal(SIGCLD, SIG_DFL);
  3491. # else /* SYSV */
  3492.       signal(SIGCHLD, SIG_DFL);
  3493. # endif /* SYSV */
  3494.       debug1("lockterminal: '%s' seems executable, execl it!\n", prg);
  3495.       if ((pid = fork()) == 0)
  3496.         {
  3497.           /* Child */
  3498.           setuid(real_uid);    /* this should be done already */
  3499.           setgid(real_gid);
  3500.           closeallfiles();    /* important: /etc/shadow may be open */
  3501.           execl(prg, "SCREEN-LOCK", NULL);
  3502.           exit(errno);
  3503.         }
  3504.       if (pid == -1)
  3505.         {
  3506. #ifdef NETHACK
  3507.           if (nethackflag)
  3508.             Msg(errno, "Cannot fork terminal - lock failed");
  3509.           else
  3510. #endif
  3511.           Msg(errno, "Cannot lock terminal - fork failed");
  3512.         }
  3513.       else
  3514.         {
  3515. #ifdef BSDWAIT
  3516.           union wait wstat;
  3517. #else
  3518.           int wstat;
  3519. #endif
  3520.           int wret;
  3521.  
  3522. #ifdef hpux
  3523.           signal(SIGCLD, SIG_DFL);
  3524. #endif
  3525.           errno = 0;
  3526.           while (((wret = wait((int *) &wstat)) != pid) ||
  3527.              ((wret == -1) && (errno == EINTR))
  3528.              )
  3529.         errno = 0;
  3530.     
  3531.           if (errno)
  3532.         {
  3533.           perror("Lock");
  3534.           sleep(2);
  3535.         }
  3536.       else if (WTERMSIG(wstat) != 0)
  3537.         {
  3538.           fprintf(stderr, "Lock: %s: Killed by signal: %d%s\n", prg,
  3539.               WTERMSIG(wstat), WIFCORESIG(wstat) ? " (Core dumped)" : "");
  3540.           sleep(2);
  3541.         }
  3542.       else if (WEXITSTATUS(wstat))
  3543.         {
  3544.           debug2("Lock: %s: return code %d\n", prg, WEXITSTATUS(wstat));
  3545.         }
  3546.           else
  3547.         printf(LockEnd);
  3548.         }
  3549.     }
  3550.   else
  3551.     {
  3552.       if (prg)
  3553.     {
  3554.           debug1("lockterminal: '%s' seems NOT executable, we use our builtin\n", prg);
  3555.     }
  3556.       else
  3557.     {
  3558.       debug("lockterminal: using buitin.\n");
  3559.     }
  3560.       screen_builtin_lck();
  3561.     }
  3562.   /* reset signals */
  3563.   for (sig = 1; sig < NSIG; sig++)
  3564.     {
  3565.       if (sigs[sig] != (sig_t(*) ()) - 1)
  3566.     signal(sig, sigs[sig]);
  3567.     }
  3568. }                /* LockTerminal */
  3569.  
  3570. /* -- original copyright by Luigi Cannelloni 1985 (luigi@faui70.UUCP) -- */
  3571. void
  3572. screen_builtin_lck()
  3573. {
  3574.   char fullname[100], *cp1, message[BUFSIZ];
  3575.   char c, *pass, mypass[9];
  3576. #ifdef SHADOWPW
  3577.   struct spwd *sss = NULL;
  3578. #endif
  3579.   int t;
  3580.  
  3581. #ifdef undef
  3582.   /* get password entry */
  3583.   if ((ppp = getpwuid(real_uid)) == NULL)
  3584.     {
  3585.       fprintf(stderr, "screen_builtin_lck: No passwd entry.\007\n");
  3586.       sleep(2);
  3587.       return;
  3588.     }
  3589.   if (!isatty(0))
  3590.     {
  3591.       fprintf(stderr, "screen_builtin_lck: Not a tty.\007\n");
  3592.       sleep(2);
  3593.       return;
  3594.     }
  3595. #endif
  3596.   pass = ppp->pw_passwd;
  3597. realpw:
  3598.   for (t = 0; t < 13; t++)
  3599.     {
  3600.       c = pass[t];
  3601.       if (!(c == '.' || c == '/' ||
  3602.             (c >= '0' && c <= '9') || 
  3603.             (c >= 'a' && c <= 'z') || 
  3604.             (c >= 'A' && c <= 'Z'))) 
  3605.         break;
  3606.     }
  3607.   if (t < 13)
  3608.     {
  3609.       debug("builtin_lock: ppp->pw_passwd bad, has it a shadow?\n");
  3610. #ifdef SHADOWPW
  3611.       setspent(); /* rewind shadow file */
  3612.       if ((sss == NULL) && (sss = getspnam(ppp->pw_name)))
  3613.         {
  3614.           pass = sss->sp_pwdp;
  3615.           goto realpw;
  3616.         }
  3617. #endif /* SHADOWPW */
  3618.       if (pass = getpass("Key:   "))
  3619.         {
  3620.           strncpy(mypass, pass, 8);
  3621.           mypass[8] = 0;
  3622.           if (*mypass == 0)
  3623.             return;
  3624.           if (pass = getpass("Again: "))
  3625.             {
  3626.               if (strcmp(mypass, pass))
  3627.                 {
  3628.                   fprintf(stderr, "Passwords don't match.\007\n");
  3629.                   sleep(2);
  3630.                   return;
  3631.                 }
  3632.             }
  3633.         }
  3634.       if (pass == 0)
  3635.         {
  3636.           fprintf(stderr, "Getpass error.\007\n");
  3637.           sleep(2);
  3638.           return;
  3639.         }
  3640.       pass = 0;
  3641.     }
  3642.  
  3643.   debug("screen_builtin_lck looking in gcos field\n");
  3644.   strcpy(fullname, ppp->pw_gecos);
  3645.   if ((cp1 = index(fullname, ',')) != NULL)
  3646.     *cp1 = '\0';
  3647.   if ((cp1 = index(fullname, '&')) != NULL)
  3648.     {
  3649.       sprintf(cp1, "%s", ppp->pw_name);
  3650.       *cp1 = islower(*cp1) ? toupper(*cp1) : *cp1;
  3651.     }
  3652.  
  3653.   sprintf(message, "Screen used by %s <%s>.\nPassword:\007",
  3654.           fullname, ppp->pw_name);
  3655.  
  3656.   /* loop here to wait for correct password */
  3657.   for (;;)
  3658.     {
  3659.       debug("screen_builtin_lck awaiting password\n");
  3660.       if ((cp1 = getpass(message)) == NULL)
  3661.         {
  3662.           AttacherFinit(SIGARG);
  3663.           /* NOTREACHED */
  3664.         }
  3665.       if (pass)
  3666.         {
  3667.           if (!strcmp(crypt(cp1, pass), pass))
  3668.             break;
  3669.         }
  3670.       else
  3671.         {
  3672.           if (!strcmp(cp1, mypass))
  3673.             break;
  3674.         }
  3675.       debug("screen_builtin_lck: NO!!!!!\n");
  3676.     }
  3677.   debug("password ok.\n");
  3678. }
  3679.  
  3680. #endif    /* LOCK */
  3681.  
  3682. /*
  3683.  * Detach now has the following modes:
  3684.  *    D_DETACH    SIG_BYE        detach backend and exit attacher
  3685.  *    D_STOP        SIG_STOP    stop attacher (and detach backend)
  3686.  *    D_REMOTE    SIG_BYE        remote detach -- reattach to new attacher
  3687.  *    D_POWER     SIG_POWER_BYE     power detach -- attacher kills his parent
  3688.  *    D_REMOTE_POWER    SIG_POWER_BYE    remote power detach -- both
  3689.  *    D_LOCK        SIG_LOCK    lock the attacher
  3690.  * (jw)
  3691.  * we always remove our utmp slots. (even when "lock" or "stop")
  3692.  * Note: Take extra care here, we may be called by unterrupt!
  3693.  */
  3694. void
  3695. Detach(mode)
  3696. int mode;
  3697. {
  3698.   int sign = 0;
  3699. #ifdef UTMPOK
  3700.   register int n;
  3701. #endif
  3702.  
  3703.   if (Detached)
  3704.     return;
  3705.   debug1("Detach(%d)\n", mode);
  3706.   if (fore && status)
  3707.     RemoveStatus();
  3708.   signal(SIGHUP, SIG_IGN);
  3709.   SetTTY(0, &OldMode);
  3710.   FinitTerm();
  3711.   switch (mode)
  3712.     {
  3713.     case D_DETACH:
  3714.       printf("\n[detached]\n");
  3715.       sign = SIG_BYE;
  3716.       break;
  3717. #ifdef BSDJOBS
  3718.     case D_STOP:
  3719.       (void) fflush(stdout);
  3720.       sign = SIG_STOP;
  3721.       break;
  3722. #endif
  3723. #ifdef REMOTE_DETACH
  3724.     case D_REMOTE:
  3725.       printf("\n[remote detached]\n");
  3726.       sign = SIG_BYE;
  3727.       break;
  3728. #endif
  3729. #ifdef POW_DETACH
  3730.     case D_POWER:
  3731.       printf("\n[power detached]\n");
  3732.       if (PowDetachString) 
  3733.         printf("%s\n", PowDetachString);
  3734.       sign = SIG_POWER_BYE;
  3735.       break;
  3736. #ifdef REMOTE_DETACH
  3737.     case D_REMOTE_POWER:
  3738.       printf("\n[remote power detached]\n");
  3739.       if (PowDetachString) 
  3740.         printf("%s\n", PowDetachString);
  3741.       sign = SIG_POWER_BYE;
  3742.       break;
  3743. #endif
  3744. #endif
  3745.     case D_LOCK:
  3746.       ClearDisplay();
  3747.       sign = SIG_LOCK;
  3748.       /* tell attacher to lock terminal with a lockprg. */
  3749.       break;
  3750.     }
  3751. #ifdef UTMPOK
  3752.   for (n = WinList; n != -1; n = wtab[n]->WinLink)
  3753.     if (wtab[n]->slot != (slot_t) -1)
  3754.       {
  3755.     RemoveUtmp(wtab[n]);
  3756.         /*
  3757.      * Set the slot to 0 to get the window
  3758.          * logged in again.
  3759.      */
  3760.     wtab[n]->slot = (slot_t) 0;
  3761.       }
  3762.   RestoreLoginSlot();
  3763. #endif
  3764.   freetty();
  3765.   (void) chmod(SockPath, /* S_IFSOCK | */ 0600); /* Flag detached-ness */
  3766.     /*
  3767.      * tell father to father what to do. We do that after we
  3768.      * freed the tty, thus getty feels more comfortable on hpux
  3769.      * if it was a power detach.
  3770.      */
  3771.   Kill(AttacherPid, sign);
  3772.   debug2("Detach: Signal %d to Attacher(%d)!\n", sign, AttacherPid);
  3773.   if (mode != D_LOCK && mode != D_STOP)
  3774.     AttacherPid = 0;
  3775.  
  3776.   Detached = 1;
  3777.   Suspended = (mode == D_STOP) ? 1 : 0;
  3778.   if (fore)
  3779.     fore->active = 0;
  3780.   debug("Detach returns, we are successfully detached.\n");
  3781. }
  3782.  
  3783. void
  3784. Kill(pid, sig)
  3785. int pid, sig;
  3786. {
  3787.   if (pid < 2)
  3788.     return;
  3789.   (void) kill(pid, sig);
  3790. }
  3791.  
  3792. static int IsSymbol(e, s)
  3793. register char *e, *s;
  3794. {
  3795.   register char *p;
  3796.   register int n;
  3797.  
  3798.   for (p = e; *p && *p != '='; ++p)
  3799.     ;
  3800.   if (*p)
  3801.     {
  3802.       *p = '\0';
  3803.       n = strcmp(e, s);
  3804.       *p = '=';
  3805.       return n == 0;
  3806.     }
  3807.   return 0;
  3808. }
  3809.  
  3810. static void MakeNewEnv()
  3811. {
  3812.   register char **op, **np;
  3813.   static char buf[MAXSTR];
  3814.  
  3815.   for (op = environ; *op; ++op)
  3816.     ;
  3817.   NewEnv = np = (char **) malloc((unsigned) (op - environ + 6 + 1) * sizeof(char **));
  3818.   if (!NewEnv)
  3819.     Msg_nomem;
  3820.   if (strlen(SockName) > MAXSTR - 5)
  3821.     SockName = "?";
  3822.   sprintf(buf, "STY=%s", SockName);
  3823.   *np++ = buf;                    /* NewEnv[0] */
  3824.   *np++ = Term;                    /* NewEnv[1] */
  3825. #ifdef TIOCSWINSZ
  3826.   np += 2;    /* room for TERMCAP and WINDOW */
  3827. #else
  3828.   np += 4;    /* room for TERMCAP WINDOW LINES COLUMNS */
  3829. #endif
  3830.  
  3831.   for (op = environ; *op; ++op)
  3832.     {
  3833.       if (!IsSymbol(*op, "TERM") && !IsSymbol(*op, "TERMCAP")
  3834.       && !IsSymbol(*op, "STY") && !IsSymbol(*op, "WINDOW")
  3835.       && !IsSymbol(*op, "SCREENCAP")
  3836. #ifndef TIOCGWINSZ
  3837.       && !IsSymbol(*op, "LINES") && !IsSymbol(*op, "COLUMNS")
  3838. #endif
  3839.       )
  3840.     *np++ = *op;
  3841.     }
  3842.   *np = 0;
  3843. }
  3844.  
  3845. void
  3846. #ifdef USEVARARGS
  3847. /*VARARGS2*/
  3848. # if defined(__STDC__)
  3849. Msg(int err, char *fmt, ...)
  3850. # else
  3851. Msg(err, fmt, va_alist)
  3852. int err;
  3853. char *fmt;
  3854. va_dcl
  3855. # endif
  3856. {
  3857.   static va_list ap = 0;
  3858. #else
  3859. /*VARARGS2*/
  3860. Msg(err, fmt, p1, p2, p3, p4, p5, p6)
  3861. int err;
  3862. char *fmt;
  3863. unsigned long p1, p2, p3, p4, p5, p6;
  3864. {
  3865. #endif
  3866.   char buf[MAXPATH*2];
  3867.   char *p = buf;
  3868.  
  3869.   if (Detached)
  3870.     return;
  3871. #ifdef USEVARARGS
  3872. # if defined(__STDC__)
  3873.   va_start(ap, fmt);
  3874. # else
  3875.   va_start(ap);
  3876. # endif
  3877.   (void) vsprintf(p, fmt, ap);
  3878.   va_end(ap);
  3879. #else
  3880.   sprintf(p, fmt, p1, p2, p3, p4, p5, p6);
  3881. #endif
  3882.   if (err)
  3883.     {
  3884.       p += strlen(p);
  3885.       if (err > 0 && err < sys_nerr)
  3886.     sprintf(p, ": %s", sys_errlist[err]);
  3887.       else
  3888.     sprintf(p, ": Error %d", err);
  3889.     }
  3890.   if (HasWindow)
  3891.     {
  3892.       debug1("Msg('%s');\n", p);
  3893.       MakeStatus(buf);
  3894.     }
  3895.   else
  3896.     {
  3897.       printf("%s\r\n", buf);
  3898.       if (DeadlyMsg)
  3899.     {
  3900.           debug1("Msg('%s') screen is not up, exiting..\n", buf);
  3901.           Kill(AttacherPid, SIG_BYE);
  3902.           eexit(1);
  3903.     }
  3904.       else
  3905.     debug1("Harmless; Msg('%s');\n", buf);
  3906.     }
  3907.   DeadlyMsg = 1;
  3908. }
  3909.  
  3910. char *Filename(s)
  3911. char *s;
  3912. {
  3913.   register char *p;
  3914.  
  3915.   if (s == NULL) 
  3916.     return s;
  3917.   p = s + strlen(s) - 1;
  3918.   while (p >= s && *p != '/')
  3919.     --p;
  3920.   return ++p;
  3921. }
  3922.  
  3923. /*
  3924.  * '^' is allowed as an escape mechanism for control characters. jw.
  3925.  */
  3926. static char *MakeWinMsg(s, n)
  3927. register char *s;
  3928. int n;
  3929. {
  3930.   static char buf[MAXSTR];
  3931.   register char *p = buf;
  3932.   register int ctrl;
  3933.  
  3934.   ctrl = 0;
  3935.   for (; *s && p < buf + MAXSTR - 1; s++, p++)
  3936.     if (ctrl)
  3937.       {
  3938.         ctrl = 0;
  3939.         if (*s == '^' || *s < 64)
  3940.           *p = *s;
  3941.         else 
  3942.           *p = *s - 64;
  3943.       }
  3944.     else
  3945.       {
  3946.         switch (*s)
  3947.           {
  3948.           case '%':
  3949.             *p = n + '0';
  3950.         break;
  3951.           case '~':
  3952.         *p = BELL;
  3953.         break;
  3954.       case '^':
  3955.         ctrl = 1;
  3956.         *p-- = '^';
  3957.         break;
  3958.           default:
  3959.         *p = *s;
  3960.         break;
  3961.           }
  3962.       }
  3963.   *p = '\0';
  3964.   return buf;
  3965. }
  3966.  
  3967.